car*_*ett 2 c# covariance contravariance
我有一些问题,我认为,差异,我不完全理解.我有一个带有两个类型参数的通用接口,如下所示:
public interface IInvoker<TParameter, TResult> {
TResult Invoke(TParameter parameter);
}
Run Code Online (Sandbox Code Playgroud)
现在,在我的情况,我想我们TA和TB抽象类,是这样的:
public abstract class AbstractParameter {
public int A { get; set; }
}
public abstract class AbstractResult {
public string X { get; set; }
}
public class Parameter1 : AbstractParameter {
public int B { get; set; }
}
public class Result1 : AbstractResult {
public string Y { get; set; }
}
// ... Many more types
Run Code Online (Sandbox Code Playgroud)
然后我想处理一组不同的实现IInvoker<,>,所以我想我可以做这样的事情
public class InvokerOne : IInvoker<Parameter1, Result1> { /* ... */ }
public class InvokerTwo : IInvoker<Parameter2, Result2> { /* ... */ }
// ..
IInvoker<AbstractParameter, AbstractResult>[] invokers = { new InvokerOne(), new InvokerTwo() };
Run Code Online (Sandbox Code Playgroud)
这不起作用,因为据我所知,IInvoker<AbstractParameter, AbstractResult>无法从IInvoker<Parameter1, Result1>(和朋友)分配.首先,我认为这是拍打一些in和out我的界面(interface IInvoker<in TParameter, out TResult>)的时间,但这没有帮助.
但我不明白为什么?据我所知,任何人都IInvoker<AbstractParameter, AbstractResult>应该可以打电话Invoke,对吧?我错过了什么?
问题是TResult类型参数是反式变量,但是你试图在你的任务中共同使用它们,例如
IInvoker<AbstractParameter, AbstractResult> i1 = new InvokerOne();
Run Code Online (Sandbox Code Playgroud)
TResult是共同变体,因此可以AbstractResult成为一个更大的类型Result1.但是,由于TParameter是反型变体,因此TParameter必须是比较小的类型Parameter1,但事实并非如此AbstractParameter.
如果以上内容有效,您可以:
class OtherParameter : AbstractParameter { ... };
IInvoker<AbstractParameter, AbstractResult> i1 = new InvokerOne();
i1.Invoke(new OtherParameter());
Run Code Online (Sandbox Code Playgroud)
这不安全.
但是你可以拥有以下内容:
public class OtherParameter1 : Parameter1 { }
IInvoker<OtherParameter1, AbstractResult> i1 = new InvokerOne();
Run Code Online (Sandbox Code Playgroud)
这里OtherParameter1可以作为参数传递,Invoke因为它始终是有效的Parameter1.