C# 协变和逆变方法 C#泛型中的in和out关键字如何使用

发布时间 - 2026-01-24 00:00:00    点击率:
协变out用于只含输出位置(如返回值、只读属性)的泛型接口或委托,如IEnumerable、Func;逆变in用于只含输入位置(如方法参数)的泛型接口或委托,如IComparer、Action。

协变 out 用在什么接口/委托上?

协变允许你用更具体的类型替换泛型参数,但前提是该参数只作为返回值出现。所以 out 只能用于输出位置:接口或委托的泛型参数如果只出现在返回类型中(比如方法返回值、只读属性的 get 访问器),才能加 out

常见可协变的接口有 IEnumerableIReadOnlyListFunc(无参返回 T 的委托)。例如:

IEnumerable strings = new List();
IEnumerable objects = strings; // ✅ 合法:string 是 object 的子类,且 IEnumerable 的 T 是 out

但不能用于 List 这种可变集合——它有 Add(T item),T 出现在输入位置,不满足协变条件。

逆变 in 为什么只能用于输入参数?

逆变允许你用更通用的类型替换泛型参数,但它要求该参数只作为输入参数出现。所以 in 只能用于方法参数、委托参数等“进来的”位置。

典型例子是 IComparerAction

IComparer comparer = Comparer.Default;
IComparer stringComparer = comparer; // ✅ 合法:string 是 object 的子类,且 IComparer 的 T 是 in

因为 Compare(T x, T y) 中的 T 只用来接收参数,不返回 T,所以可以安全地“向上兼容”。

注意:一个泛型参数不能同时是 inout;也不能在同一个接口里既当输入又当输出(否则编译器会报错)。

自定义接口加 inout 的硬性限制

你不能随便给任意泛型接口加 inout,编译器会严格检查所有成员中的使用位置:

  • out T → 所有 T 必须出现在仅输出位置:返回类型、只读属性、委托返回值等
  • in T → 所有 T 必须出现在仅输入位置:方法参数、委托参数、ref/out 参数的类型不允许(它们是双向的,违反纯输入)

例如这个接口无法标记为 out

interface Bad {
    T Get();           // ✅ 输出
    void Set(T value); // ❌ 编译错误:T 出现在输入位置
}

委托中 FuncAction 的 in/out 已经预设好了

不必自己写 delegate 声明,.NET 内置委托已经按规则标注:

  • Func:TResult 是 out
  • Func:T 是 in,TResult 是 out
  • Action:T 是 in
  • Predicate:T 是 in
  • Comparison:T 是 in

这意味着你可以直接利用这些协变/逆变能力做类型转换,但别试图把 Action 赋给 Action——那是反的,会编译失败

;正确的是 Action action = x => Console.WriteLine(x); Action stringAction = action;(因为 string 可安全传给期望 object 的地方)。

真正容易被忽略的是:协变和逆变只对引用类型生效。如果你用 intstruct,哪怕满足位置要求,也无法进行这种隐式转换——编译器不会报错,但转换语句根本不会通过类型检查。


# c#  # 编译错误  # .net  # 隐式转换  # 为什么  # red  # gate  # String  # Object  # int  # 接口  # 引用类型  # Struct  # 访问器  # Delegate  # 委托  # 泛型  # 类型转换  # console  # 出现在  # 逆变  # 返回值  # 的是  # 你用  # 子类  # 报错  # 也不  # 好了  # 你可以 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 桂林网站制作公司有哪些,桂林马拉松怎么报名?  专业商城网站制作公司有哪些,pi商城官网是哪个?  Laravel事件和监听器如何实现_Laravel Events & Listeners解耦应用的实战教程  javascript如何操作浏览器历史记录_怎样实现无刷新导航  Laravel如何使用Telescope进行调试?(安装和使用教程)  油猴 教程,油猴搜脚本为什么会网页无法显示?  制作旅游网站html,怎样注册旅游网站?  公司门户网站制作流程,华为官网怎么做?  Win11任务栏卡死怎么办 Windows11任务栏无反应解决方法【教程】  Laravel如何使用withoutEvents方法临时禁用模型事件  免费的流程图制作网站有哪些,2025年教师初级职称申报网上流程?  Win11关机界面怎么改_Win11自定义关机画面设置【工具】  如何用搬瓦工VPS快速搭建个人网站?  怎样使用JSON进行数据交换_它有什么限制  Laravel 419 page expired怎么解决_Laravel CSRF令牌过期处理  Laravel Livewire是什么_使用Laravel Livewire构建动态前端界面  如何挑选最适合建站的高性能VPS主机?  如何在 Pandas 中基于一列条件计算另一列的分组均值  Linux系统命令中tree命令详解  移动端手机网站制作软件,掌上时代,移动端网站的谷歌SEO该如何做?  Laravel如何设置定时任务(Cron Job)_Laravel调度器与任务计划配置  Laravel怎么配置不同环境的数据库_Laravel本地测试与生产环境动态切换【方法】  Laravel怎么返回JSON格式数据_Laravel API资源Response响应格式化【技巧】  PHP 500报错的快速解决方法  Windows10如何删除恢复分区_Win10 Diskpart命令强制删除分区  HTML透明颜色代码怎么让图片透明_给img元素加透明色的技巧【方法】  谷歌浏览器如何更改浏览器主题 Google Chrome主题设置教程  极客网站有哪些,DoNews、36氪、爱范儿、虎嗅、雷锋网、极客公园这些互联网媒体网站有什么差异?  如何基于PHP生成高效IDC网络公司建站源码?  Laravel怎么实现一对多关联查询_Laravel Eloquent模型关系定义与预加载【实战】  Java Adapter 适配器模式(类适配器,对象适配器)优缺点对比  Python图片处理进阶教程_Pillow滤镜与图像增强  Laravel如何使用Vite进行前端资源打包?(配置示例)  Laravel如何处理CORS跨域问题_Laravel项目CORS配置与解决方案  Laravel怎么防止CSRF攻击_Laravel CSRF保护中间件原理与实践  Laravel观察者模式如何使用_Laravel Model Observer配置  如何在腾讯云服务器快速搭建个人网站?  HTML5空格和margin有啥区别_空格与外边距的使用场景【说明】  nodejs redis 发布订阅机制封装实现方法及实例代码  laravel怎么使用数据库工厂(Factory)生成带有关联模型的数据_laravel Factory生成关联数据方法  如何在企业微信快速生成手机电脑官网?  动图在线制作网站有哪些,滑动动图图集怎么做?  制作无缝贴图网站有哪些,3dmax无缝贴图怎么调?  如何正确选择百度移动适配建站域名?  Swift中循环语句中的转移语句 break 和 continue  Laravel如何实现本地化和多语言支持_Laravel多语言配置与翻译文件管理  如何在IIS7上新建站点并设置安全权限?  网站页面设计需要考虑到这些问题  安克发布新款氮化镓充电宝:体积缩小 30%,支持 200W 输出  学生网站制作软件,一个12岁的学生写小说,应该去什么样的网站?