0

B抽象クラスの特殊化であるクラスのインスタンスがありますA<TInput, TOutput>Bさまざまな入力と出力を使用して実装したため、クラスにはいくつかのバリエーションがあります。

TInputそして、特定の入力クラスと出力クラスに制約されているので、それらをととTOutput呼びましょう。IO

Activator.CreateInstanceBを使用してインスタンス化していますが、オブジェクトが返されるため、にキャストする必要があります。これが基本クラス(この場合)として機能することを期待しています。A<I, O>IOB<SpecialisationOfI, SpecalisationOfO>

このキャストは明らかに無効であるため、これは失敗する場所です。

擬似コード:

abstract class I  { }
abstract class O { }

abstract class A<TInput, TOutput> 
  where TInput : I
  where TOutput : O
{ 
  abstract TOutput Foo(TInput bar);
}

class Input : I { }
class Output : O { }

class B : A<Input, Output> { }

A<I, O> instance = (A<I, O>)Activator.CreateInstance(typeOfB); // <-- fail
instance.Foo(input);

これを機能させることは可能ですか?ありがとうございました!

編集私が与えられた答えに基づいて、共分散に基づいてコードを大幅に再構築することでこれを解決しました:私はインターフェイスに移動Fooしました:A

interface IA<TResult> {
   TResult Foo(object input);
}

class A<TInput, TOutput> : IA<TOutput>
  where TInput : I
  where TOutput : O {

  public TOutput Foo(object input) {
     if (!(input is TInput)) {
       throw new ArgumentException("input");
     }

     return FooImpl(input as TInput);
  }

  protected abstract TOutput FooImpl(TInput input);
}

var instance = (IA<Output>) Activator.CreateInstance(type);
instance.Foo(input);

私とあなたの洞察を共有してくれてありがとう!

4

1 に答える 1

3

これは、インスタンスの作成方法とは関係ありません。一般的な分散の問題です。あなたが本質的にやろうとしていることはこれに似ています:

List<object> objects = new List<string>();

そして、それが無効である理由は、コードの次の行が(一般的に)次のようになる可能性があるためです。

objects.Add(new object());

それが本当にタイプのリストに追加しようとしているのなら、それはList<string>悪いニュースです。

これで、抽象クラスからインターフェイスに変更し、C#4を使用している場合は、ジェネリック共分散ジェネリック反変性を使用できます。

interface class A<in TInput, out TOutput> 
  where TInput : I
  where TOutput : O
{ 
  abstract TOutput Foo(TInput bar);
}

ただし、入力と出力の両方を共変的に使用しようとしているため、コードではまだ機能しません。クラスには次のようなメソッドがあります。B

Output Foo(Input bar);

...つまり、タイプの入力が必要Inputです。しかし、もしあなたがそれを持っているなら、それはどんな実装でもA<I, O>機能するはずです:I

A<I, O> x = new B();                // Invalid, as discussed, to prevent...
O output = x.Foo(new SomeOtherI()); // ... this line
于 2012-09-01T13:46:18.467 に答える