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

在微软提供的逆变示例中,我遗漏了哪些关键内容?

解惑C#中的逆变实践困惑

我太懂这种“看书时觉得概念清晰,上手写代码就懵圈”的感觉了——逆变的抽象性确实容易让理论和实践脱节。咱们从你提到的委托场景入手,一步步把它掰碎了说:

先抓逆变的核心本质

逆变的核心就是:允许用「更宽泛的类型处理器」来处理「更具体的类型数据」,它专门作用于输入型泛型参数(也就是用in关键字标记的参数,比如委托的入参、接口方法的参数)。

结合你的代码片段拆解(我补全了截断的部分,应该符合你的场景)

假设你的代码是类似这样的委托定义:

using static System.Console;
namespace CSharpTests
{
    class Program
    {
        // 带逆变参数的委托(in标记输入型参数)
        delegate void Action<in T>(T input);

        // 一个能处理所有object的方法
        static void PrintObject(object obj)
        {
            WriteLine($"输出内容: {obj}");
        }

        static void Main(string[] args)
        {
            // 重点:这里就是逆变的实际体现!
            // Action<string>期望接收一个参数为string的方法,但我们赋值了参数为object的PrintObject
            Action<string> stringPrinter = PrintObject;
            stringPrinter("测试逆变");
        }
    }
}

运行这段代码你会发现完全没问题——为什么?因为object是string的父类,能处理所有object的方法,自然能处理更具体的string。逆变就是帮我们完成了这个类型安全的转换,不用手动写强制转换。

别和协变搞混,抓准「输入/输出」的区别

很多人混淆逆变和协变,其实只要记住:

  • 协变(out关键字):针对输出型参数(比如Func的返回值),允许用更具体的类型替代宽泛的类型(比如用Func<string>赋值给Func<object>)
  • 逆变(in关键字):针对输入型参数(比如委托的入参),允许用更宽泛的类型替代具体的类型(比如上面的例子)

再给个实际开发中的场景加深理解

比如.NET内置的IComparer<in T>接口就是逆变的。假设你写了一个ObjectComparer用来比较任意object的哈希值,那它直接就能用来排序List<string>或者List<int>——因为能比较所有object的逻辑,肯定能比较它的子类。这就是逆变在实际开发中帮我们复用代码的地方。

内容的提问来源于stack exchange,提问作者Konstantin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:24:04