0

我有一个 class 的实例B,它是一个抽象类的特化A<TInput, TOutput>。class 有几种变体B,因为我已经用各种输入和输出实现了它。

TInput并且TOutput受限于特定的输入和输出类,我们称它们为Iand O

我正在B使用Activator.CreateInstance进行实例化,但由于它返回一个对象,我需要将其转换为A<I, O>. 我希望它可以作为基类工作IO在这种情况下B<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);

有可能完成这项工作吗?谢谢!

编辑根据我得到的答案,我已经通过基于协方差显着重构代码解决了这个问题:我FooA一个界面转移:

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());

如果那是试图添加到一个真正属于 type的列表中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);

...换句话说,它需要输入 type 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 回答