从How to reflect an interfaced type<t> at runtime开始,我有一个类型的实例,我知道它是从基类型DataPointProcessorBase继承而来的 这个基类相对简单
public abstract class DataPointProcessorBase<T> : IDataPointProcessor<T> where T : class, IDataPointInput, new()
{
public abstract DataPointOutputBase GetOutput(T input);
}
Age_Input实现接口,Age_Processor设置为接收它
public class Age_Input : DataPointInputBase, IDataPointInput
{
public int AgeExact { get; set; }
}
public class Age_Processor : DataPointProcessorBase<Age_Input>
{
...
}
使用反射,我可以正确地进行反射,所以我可以调用GetOutput()
任何想法,为什么我不能进入下面的声明?
var instance = Activator.CreateInstance(type);
if (instance is IDataPointProcessor<IDataPointInput>)//why can I not cast interface here?
{
//false
}
if (instance is IDataPointProcessor<Age_Input>)//hard-coded - works fine
{
var processor = instance as IDataPointProcessor<Age_Input>;
Age_Input temp = item as Age_Input;
if (temp is IDataPointInput)
{
//also true
}
var result = processor.GetOutput(temp);
}
答案 0 :(得分:9)
每天都会问这个问题。再一次!
当你需要一篮子水果时,是否可以使用一篮子苹果?没有。
为什么不呢?因为你可以把香蕉放入一篮子水果中,但你不能把香蕉放入一篮子苹果中。
因此,如果需要一篮子水果,你就不能使用一篮子苹果。
同样地,一篮子水果不能用作一篮子苹果,因为它可能已含有香蕉。
如果C<X>
可以用作C<Y>
,则“X
可以用作Y
的关系称为协方差 ,C#仅在非常有限的情况下支持协方差:
C<T>
必须是接口或代理X
和Y
都必须是引用类型。在你的情况下,你有第一和第四个属性,但你没有第二个和第三个属性。
将IDataPointProcessor<T>
标记为:
interface IDataPointProcessor<out T>
这意味着大致“T仅用于输出位置,从不输入位置”。如果篮子没有能力添加水果,那么反对意见 - 你不能把香蕉放入一篮子苹果 - 消失,它变得合法。
如果编译成功,那么协方差将开始在IDataPointProcessor
上工作。如果没有,您可能会在T
可以在中流动的位置使用T
。规则比我在这里总结的要简单一些;如果你需要详细的描述,我在这里写了一个:https://blogs.msdn.microsoft.com/ericlippert/2009/12/03/exact-rules-for-variance-validity/
这就是为什么你可以使用IEnumerable<Giraffe>
作为IEnumerable<Animal>
- 满足所有四个条件。
答案 1 :(得分:0)
我通过不使用反射完全避免这个问题来解决这个问题和How to reflect an interfaced type<t> at runtime。如果有兴趣的话,该页面上的完整答案
感谢您的所有时间
@Eric 我确实事先找到了你的文章,但那时我的头部受伤了!
答案 2 :(得分:-1)
根据我的理解,泛型类型在C#编译器中的工作方式是在编译时在这些泛型参数中使用的强类型类型(意味着它们在代码中使用)是作为强类型类动态生成的(可能在MSIL层上。)
因此,在运行时,您的对象没有具有泛型类型的继承类型,而是具有强类型的继承类型。
您可以为每种可能的强类型类型构建一个switch case并尝试强制转换它。