C#泛型委托:无法将派生类型参数委托赋值给基类型参数委托
问题原因解释
核心逻辑:你搞反了逆变的赋值方向
泛型参数的不同修饰符对应完全不同的赋值规则:
- 用
out修饰的返回值参数(协变):支持子类类型 → 父类类型的赋值,和常规类型转换方向一致,所以你第一处将返回值为string的sgd1赋值给返回值为object的sgd2是合法的。 - 用
in修饰的输入参数(逆变):支持父类类型参数的委托 → 子类类型参数的委托的赋值,和常规类型转换方向相反,这是你赋值失败的核心原因。
你用到的代码:
class Program { // 这里A是逆变参数(in修饰),R是协变参数(out修饰) public delegate R SampleGenericDelegate<in A, out R>(A a); static void Main(string[] args) { SampleGenericDelegate<string, string> sgd1= TakesObjectReturnsString; SampleGenericDelegate<string, object> sgd2= sgd1; // 协变场景合法:返回值string是object的子类 SampleGenericDelegate<string, string> sgd3= TakesObjectReturnsString; SampleGenericDelegate<object, string> sgd4= sgd3; // 赋值方向错误,所以报错 } public static string TakesObjectReturnsString(object s) { return ""; } }
报错的具体原因
你当前的sgd3是输入参数为string的委托,意味着它只能接收string类型的入参;而sgd4的输入参数是object,意味着它可以接收任意类型的入参。如果允许把sgd3赋值给sgd4,就会出现逻辑漏洞:你调用sgd4(123)的时候,入参是int类型,而实际执行的sgd3只能处理string,就会出现类型错误,所以编译器直接禁止了这种不安全的赋值。
正确的逆变写法
如果要触发合法的逆变场景,你应该反过来赋值:
// 先声明输入参数为更宽泛的object类型的委托 SampleGenericDelegate<object, string> sgdX = TakesObjectReturnsString; // 可以安全赋值给输入参数为更具体的string类型的委托 SampleGenericDelegate<string, string> sgdY = sgdX;
这时候调用sgdY时只能传入string类型的参数,而sgdX的逻辑可以处理所有object类型,string肯定属于object,完全不会有类型安全问题,符合逆变的规则。
内容的提问来源于stack exchange,提问作者ravikiran
相关产品推荐
相关产品推荐

