You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 00:54:05