2017-01-25 12 views
0

私はかなり多くの可能な回答を読み、私のニーズに合ったものは見つけられませんでした。ジェネリックインターフェイスの非汎用実装

ジェネリックインターフェイスを宣言しようとしていて、ジェネリックでない実装クラスを別にして、このクラスを同じコンテキストで使用しようとしています。

これは私がこれまで持っているものです。

インタフェース

public interface WeirdType { } 
public class WeirdType1 : WeirdType { } 
public class WeirdType2 : WeirdType { } 


public interface IGenericInterface<T> 
{ 
    T GiveT(); 
    void TakeItBack(T data); 
} 

public class NonGenericImplementation1 : IGenericInterface<WeirdType1> 
{ 
    public WeirdType1 GiveT() { return new WeirdType1(); } 
    public void TakeItBack(WeirdType1 data) { Console.WriteLine("Got it back 1"); } 
} 

public class NonGenericImplementation2 : IGenericInterface<WeirdType2> 
{ 
    public WeirdType2 GiveT() { return new WeirdType2(); } 
    public void TakeItBack(WeirdType2 data) { Console.WriteLine("Got it back 2"); } 
} 

使用

List<IGenericInterface<WeirdType>> implementations = new List<IGenericInterface<WeirdType>> 
{ 
    new NonGenericImplementation1(), 
    new NonGenericImplementation2() 
}; 

foreach (var impl in implementations) 
{ 
    WeirdType x = impl.GiveT(); 
    impl.TakeItBack(x); 
} 

実装は、これは私がスローされます

また、黒いキャスティングマジックがコンパイルによって私を取得しても、同じ理由で実行時にクラッシュします。

私は私の実際の問題の異なった方法の多くを解決することができるので、完全に別の解決策が実際にはありませんどのようなC#のタイピングのためにこれを不可能にする、および/またはそれがスムーズに

を成し遂げるために少し複雑なパターンを示唆して理解させます私は

を探していますと、明らかに実際の答えはすでにいつものように、それはまだ私が助けるために全力を尽くします、コンテキストなしで適切であることを難しい

+0

:純粋にゲッターを使用しているとき、あなたはインターフェイスの共変を作ることができますそれを 'public interface IGenericInterface 'と宣言します。リストの実装はそのまま受け入れられますが、受け入れられた答えで説明されている理由でTakeItBack関数が許可されません(例えば 'void TakeItBack(WeirdType data);と定義されていない限り) –

+0

私の実装のそれぞれは、それ自体で!つまり、私の使用中にWeirdtypeの代わりに(impl.T)のようなものを使うことができたら、これは型付けの観点から正しく動作するはずです。 –

答えて

0

implementationsから何かを取り除くと、それはタイプIGenericInterface<WeirdType>であることがわかります。つまり、GiveTに電話をしてWeirdTypeTakeItBackになると、WeirdTypeとなります。特に

これは、次の両方が動作しなければならないことを意味する:implはタイプNonGenericImplementation1であれば

impl.TakeItBack(new WeirdType1()); 
impl.TakeItBack(new WeirdType2()); 

は今、2番目が有効ではありません、それはタイプNonGenericImplementation2であるならば、最初は有効ではありません。

これはNonGenericImplementation1がタイプIGenericInterface<WeirdType>であり、NonGenericImplementation2であると主張することを許可されていないことを意味します。

+1

これは意味があり、コンパイラが自分のコードを受け入れない理由は明らかです。 –

0

を無駄に時間を気の毒に存在している場合。

'Argument Type NonGenericImplementation1はIGenericInterfaceに割り当てられません'というエラーは、C#ではコレクションのさまざまなメンバーが同じタイプでなければなりません。

しかし、なぜあなたは宣言しない:

public class NonGenericImplementation1 : IGenericInterface<WeirdType1> 
public class NonGenericImplementation2 : IGenericInterface<WeirdType2> 

の代わりに:このように

public class NonGenericImplementation1 : IGenericInterface<WeirdType> 
public class NonGenericImplementation2 : IGenericInterface<WeirdType> 

を、すべてのあなたの例のコードはまだ動作し、両方のクラスが同じインターフェイスを実装しますので、あなた

List<IGenericInterface<WeirdType>> implementations = new List<IGenericInterface<WeirdType>> 
      { 
       new NonGenericImplementation1(), 
       new NonGenericImplementation2() 
      }; 

希望することができます。

0

IGenericInterface<WeirdType1>は、WeirdType1WeirdTypeであっても、IGenericInterface<WeirdType>ではありません。

0

IGenericInterfaceを実装する非汎用クラスはありません。

"implements"コレクションは、上記のインタフェースを実装するタイプのオブジェクトのみを受け入れることができます。

これはGenericsの美点です。それらは強く型付けされており、ジェネリックスのジェネリックスを扱うときは、はるかに挑戦的になります。しかし、そこから脱出する方法はありません。

まず、Generic Listは、IGenericInterfaceを実装していないタイプのオブジェクトを受け入れません。次に、あなたがその種のクラスを持っているときに、型が "WeirdType"から継承されていても、 "WeirdType"以外の型でインスタンス化されるオブジェクトは許可されません。

ジェネリックスでの継承は、第1レベルで役立ちますが、それを超えません。

問題の解決策があります。それは100%有効な解決策ではなく、多くのOOP専門家はこれに同意しませんが、あなたが望むクラス構造を持ち、あなたが望むように動作します。

以下のようにサブクラスを作成する必要があります。

public class GenericClass<T> : IGenericInterface<T> where T : WeirdType 
{ 
    public virtual T GiveT() 
    { 
     return default(T); 
    } 

    public virtual void TakeItBack(T data) 
    { 

    } 
} 

public class NonGenericClass1 : GenericClass<WeirdType1>, IGenericInterface<WeirdType> 
{ 
    public override WeirdType1 GiveT() 
    { 
     return new WeirdType1(); 
    } 

    public void TakeItBack(WeirdType data) 
    { 
     Console.WriteLine("Got it back 1"); 
    } 

    public override void TakeItBack(WeirdType1 data) 
    { 
     this.TakeItBack(data); 
    } 

    WeirdType IGenericInterface<WeirdType>.GiveT() 
    { 
     return GiveT(); 
    } 
} 

public class NonGenericClass2 : GenericClass<WeirdType2>, IGenericInterface<WeirdType> 
{ 
    public WeirdType2 GiveT() 
    { 
     return new WeirdType2(); 
    } 

    public void TakeItBack(WeirdType data) 
    { 
     Console.WriteLine("Got it back 2"); 

    } 

    public override void TakeItBack(WeirdType2 data) 
    { 
     this.TakeItBack(data); 
    } 

    WeirdType IGenericInterface<WeirdType>.GiveT() 
    { 
     return this.GiveT(); 
    } 
} 

ここで、Genericインターフェイスのコレクションを初期化し、サブクラスのオブジェクトを追加することができます。

var obj1 = new NonGenericClass1(); 
     var obj2 = new NonGenericClass2(); 
     List<IGenericInterface<WeirdType>> implementations = new List<IGenericInterface<WeirdType>> 
     { 
      obj1, obj2 
     }; 

     foreach (var impl in implementations) 
     { 
      WeirdType x = impl.GiveT(); 
      impl.TakeItBack(x); 
     } 

これで問題が解決するはずです。

0

あなたのご意見をお寄せいただき、ありがとうございました。可能な限り定型化されていないコードを繰り返さないようにしました。

私が行った解決策は、追加のインターフェイスを実装する抽象クラスを追加することでした。

これは、ジェネリックのための型にとらわれないコードを書くことができなければならないので、実際のクラスとインターフェースのコード/階層を変更したり、

これは拡張メソッドとジェネリックスの型なしリストで可能ですが、後でC#ではサポートされません。

HERESに余分なコード:

public interface IComplexable { void DoComplexStuff(); } 

public abstract class GenericImplementation<T> : IGenericInterface<T>, IComplexable 
{ 
    public abstract T GiveT(); 
    public abstract void TakeItBack(T data); 

    public void DoComplexStuff() 
    { 
     T x = GiveT(); 
     TakeItBack(x); 
    } 
} 

クラスの宣言:

public class NonGenericImplementation1 : GenericImplementation<WeirdType1> 
public class NonGenericImplementation2 : GenericImplementation<WeirdType2> 

使用法:レコードの

var impl = new IComplexable[] { new NonGenericImplementation1(),new NonGenericImplementation2() }; 
foreach (var complexable in impl) 
{ 
    complexable.DoComplexStuff(); 
} 
関連する問題