2016-05-18 7 views
1

私は抽象クラスを持っています。ジェネリック型引数をとり、他の2つのクラスHumanとSpiderで拡張されたクリーチャーです。各サブクラスはその親のジェネリック型を定義します。ジェネリッククラスを拡張するクラスのジェネリック型パラメータを渡さないようにする

親クラスの参照としてサブクラスをメソッドに渡す方法が残っています。

public interface IDamagable 
{ 
    void OnSimpleHit(); 
} 

public interface IStabAble : IDamagable 
{ 
    void OnKnifeStab(); 
} 

public interface ISlapAble : IDamagable 
{ 
    void OnSlap(); 
} 

public abstract class Creature<T> where T : IDamagable 
{ 
    public abstract void Init(T damageListener); 
} 

public abstract class Human : Creature<ISlapAble> 
{ 

} 

public abstract class Spider : Creature<IStabAble> 
{ 

} 

public class MainClass 
{ 
    public void Test() 
    { 
     List<Spider> spiderList = new List<Spider>(); 
     List<Human> humanList = new List<Human>(); 

     PrintList<IDamagable>(spiderList); // Argument `#1' cannot convert 
     //`System.Collections.Generic.List<newAd.B_A_A>' expression 
     //to type `System.Collections.Generic.List<newAd.A_A<newAd.I_B>>' 
    } 

    protected void PrintList<T>(List<Creature<T>> list) 
    { 

    } 
} 

このdoesntのスローエラーがprintlistは

protected void PrintList<T,U>(List<T> list) where T : Creature<U> where U : IDamagable 
    { 

    } 

2つのジェネリック引数を取ったが、Tがすでにタイプパラメータ、例えばスパイダーとしてUで構築したとして、私は、再びUに合格しない場合すでに定義されているクリーチャーがIStabAbleの型パラメータを取るように定義されています。

基本的に、私は、SpiderとHumanの両方を最小限の数の汎用パラメータで処理できるようにメソッドを記述する方法についています。
ありがとう

+6

クラス階層の関係を理解し​​やすいように名前を変更することを検討してください。あなたのコードを理解するだけで、頭痛を覚えるのであれば、多くの助けを得ることはありません。 I_A' – InBetween

+0

Tはどこ '無効がprintlist (IEnumerableを>リスト)に' PrintList'メソッドのシグネチャを変更してみてください –

+2

はクラスとインタフェースを改名など @YacoubMassad私はIEnumerableをにリストを変更すると何がどのように変化するかを理解していない: – Farhan

答えて

2

PrintListは、リストへの読み取り専用の転送専用アクセスが必要であると仮定しています。

void PrintList<T>(IEnumerable<Creature<T>> list) where T: IDamagable 
{ 
    //... 
} 

そして、このようにそれを呼び出す:IEnumerable<T>におけるジェネリック型パラメータTcovariantあるので

PrintList(spiderList); 

、この

ソリューションはPrintList方法は、このようなIEnumerable<Creature<T>>を受け入れるようにすることです働くでしょう。

特殊なケースでは、.NET 2.0(共変タイプのパラメータをサポートしていない)を使用しているため、このソリューションは機能しません。ここでは、回避策です:

は(.NET 3.5で、我々はすでに拡張メソッドとして、このような方法を持っている)、このようなさまざまなアイテムの種類とenumerablesの間で変換することができCastメソッドを作成します。

public static IEnumerable<U> Cast<T, U>(IEnumerable<T> source) where T : U 
{ 
    foreach (var item in source) 
    { 
     yield return item; 
    } 
} 

と使用

PrintList(Cast<Spider, Creature<IStabAble>>(spiderList)); 
+0

したがって、使用するジェネリックタイプの最小数は2です。しかし、ランダムリストインデックスを使用するつもりです明確化の最後のビットについて、私が提案したバリエーションは、 'U ':IDamagable { }'のように、T:Creature (ここで、U:IDamagableのリストはである)を提案したバリエーションも効率的です。 ..? – Farhan

+0

私の 'PrintList'のバージョンは単一の型パラメータを持っていますが、あなたが呼び出す前に、正しい型に列挙できる。あなたのバージョンは、キャストを伴わないので、少し効率的です。インデックスで項目にアクセスする必要がある場合は、 'List'を使用しているので、2つのパラメータが必要です。 –

+0

ありがとうございました! – Farhan

関連する問題