使用泛型将对象强制转换为类

时间:2012-09-01 13:39:32

标签: c# .net

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

TInputTOutput受限于特定的输入和输出类,我们称之为IO

我使用Activator.CreateInstance实例化B,但由于它返回了一个对象,我需要将其强制转换为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);

感谢您与我分享您的见解!

1 个答案:

答案 0 :(得分:3)

这与您创建实例的方式无关 - 这是generic variance的问题。你基本上要做的就是这样:

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