在微软提供的逆变示例中,我遗漏了哪些关键内容?
解惑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
相关产品推荐
相关产品推荐

