当泛型方法推断,扩展方法遇到泛型类型in/out时。。。
说到泛型方法,这个是.net 2.0的时候引入的一个重要功能,c#2.0也对此作了非常好的支持,可以不需要显试的声明泛型类型,让编译器自动推断,例如:
void F<T>(T value){}
//...
int i = ;
F(i);
此时,编译器可以自动推导出这里的T就是int,这极大的方便了我们写代码的效率。
说到扩展方法,这个是.net 3.5的时候引入的另一个重要功能,c#3.0也在linq中大量的应用这个功能,当扩展方法是扩展一个泛型的类型时,显然也不需要我们指定具体的泛型类型,编译器会为我们自动推断,例如:
static void F<T>(this List<T> list){}
//...
List<int> list = new List<int>();
list.F();
最后说到协变和逆变(也就是c#中的in/out),这个是.net 4.0的时候引入的一个重要的功能,例如:
Func<string> foo = () => "Foo";
Func<object> bar = foo;
然后,我们将泛型方法推断和协变和逆变放在一起:
public static void Foo(this Action<string> action){}
//...
Action<object> action = o => {};
action.Foo();
看起来很不错,不过要是遇到些复杂点的会怎么样?
public static void Foo(this IEnumerable<IEnumerable<object>> that) {}
//...
List<List<string>> bar = new List<List<string>>();
bar.Foo();
看到这里相信所有都为c#的in/out拍手叫好,不过别急,除了out+out我们还可以玩令人抓狂的in+in:
public static void Foo(this Action<Action<object>> that) {}
//...
Action<Action<string>> action = a => a("O_O");
action.Foo();
看到这里有没有发现什么问题?如果你没觉得有什么不舒服的感觉,说明你一定是懂协变和逆变的高手或是完全不懂的初学者。
先想下定义:Action<in T>,T 是in的,也就是Action<object>里面的object可以被string这样更具体的类型替代,而这里Action<Action<string>>里面的Action<string>被Action<object>替代了,怎么看都感觉有些怪异,不过在细细品味一下,就可以发现这个结果是完全合理的。string虽然比object更具体,不过一个接受string的方法可比一个接受object的方法更抽象,所以可以简单的得到一个结论:in+in=>out
文章要是到这里结束,估计很多人就认为本文是对c#的无比赞美了吧,不过,重点是这里,别忘了,多个泛型参数可以玩出很多猥琐的东西,例如,双/多泛型锁定(随便起的名字):
public static void Foo<T>(this Action<T, T> that) {}
//...
Action<string, object> action = (s, o) => {};
action.Foo();
c#编译器对扩展方法支持的确是有一手,这么变态的T也可以被推断出是object,不得不佩服一把,再来看看out的情况(别忘了前面的结论in+in=>out):
public static void Foo<T>(this Action<Action<T>, Action<T>> that) {}
//...
Action<Action<string, object>> action = (s, o) => {};
action.Foo();
c#编译器依然表现出专业的结果,正确的推断出了T应当是string,不过,泛型方法的类型推断却完全是另外一番风景:
public void Foo<T>(Action<T, T> that) {}
//...
Action<string, object> action = (s, o) => {};
Foo(action); // failed.
Foo<object>(action); // failed.
Foo((Action<object, object>)action); // succeeded.
看到这个结果是不是想大骂c#编译器:这也太山寨了吧。
别急,我们还可以玩得更加浮云:
public static Foo<T>(this Action<Action<T>, Action<T>> that) {}
// ...
Action<Action<List<string>>, Action<ArrayList>> bar = null;
bar.Foo(); // failed.
bar.Foo<IEnumerable>(); // succeeded.
或者这个:
public static Foo<T>(this Action<T, T> that) {}
// ...
Action<IEnumerable<char>, IComparable<string>> action = null;
action.Foo(); // failed.
action.Foo<string>(); // succeeded.
c#编译器显然不想瞎猜T的类型是什么,要求必须编程者明确指出T的具体类型。
当泛型方法推断,扩展方法遇到泛型类型in/out时。。。的更多相关文章
- C#扫盲之:带你掌握C#的扩展方法、以及探讨扩展方法的本质、注意事项
1.为什么需要扩展方法 .NET3.5给我们提供了扩展方法的概念,它的功能是在不修改要添加类型的原有结构时,允许你为类或结构添加新方法. 思考:那么究竟为什么需要扩展方法呢,为什么不直接修改原有类型呢 ...
- C# Note21: 扩展方法(Extension Method)及其应用
前言 今天在开会时提到的一个概念,入职3个多月多注重在项目中使用C#的编程知识,一直没有很认真地过一遍C#的全部语法,当我们新人被问及是否了解Extension Method时,一时之间竟不能很通俗准 ...
- 【转载】C#扫盲之:带你掌握C#的扩展方法、以及探讨扩展方法的本质、注意事项
1.为什么需要扩展方法 .NET3.5给我们提供了扩展方法的概念,它的功能是在不修改要添加类型的原有结构时,允许你为类或结构添加新方法. 思考:那么究竟为什么需要扩展方法呢,为什么不直接修改原有类型呢 ...
- 【开源】OSharp框架解说系列(3):扩展方法
OSharp是什么? OSharp是个快速开发框架,但不是一个大而全的包罗万象的框架,严格的说,OSharp中什么都没有实现.与其他大而全的框架最大的不同点,就是OSharp只做抽象封装,不做实现.依 ...
- .NET 扩展方法 (二)
上一篇随笔 .NET 扩展方法 (一) 已经对 扩展方法有了大致的介绍,这篇算是一个补充,让我们来看一下扩展方法的几个细节: 一.扩展方法具有继承性 当使用扩展方法扩展一个类型的时候,其也扩展了派生类 ...
- C#基础---扩展方法的应用
最近对扩展方法比较感兴趣,就看了看资料,记录一下扩展方法的几种方法. 一. 扩展方法的基本使用: Note: 1. 扩展方法必须在静态类中, 2 扩展方法必须声明静态方法,3 扩展方法里面不能调用其 ...
- [读书笔记]C#学习笔记五: C#3.0自动属性,匿名属性及扩展方法
前言 这一章算是看这本书最大的收获了, Lambda表达式让人用着屡试不爽, C#3.0可谓颠覆了我们的代码编写风格. 因为Lambda所需篇幅挺大, 所以先总结C#3.0智能编译器给我们带来的诸多好 ...
- 从扩展方法到匿名方法再到LINQ
1.首先我们应该知道什么是扩展方法: 扩展方法使您能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型. 扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样 ...
- C#学习笔记四: C#3.0自动属性&匿名属性及扩展方法
前言 这一章算是看这本书最大的收获了, Lambda表达式让人用着屡试不爽, C#3.0可谓颠覆了我们的代码编写风格. 因为Lambda所需篇幅挺大, 所以先总结C#3.0智能编译器给我们带来的诸多好 ...
随机推荐
- Struts2(3) —— 数据处理
Struts2框架框架使用OGNL语言和值栈技术实现数据的流转处理. 值栈就相当于一个容器,用来存放数据,而OGNL是一种快速查询数据的语言. 值栈:ValueStack一种数据结构,操作数据的方式为 ...
- npm 初学者教程
Node.js 让 JavaScript 编写服务器端应用程序成为可能.它建立在 JavaScript V8(C++ 编写的) 运行时之上,所以它很快.最初,它旨在为应用程序提供服务器环境,但是开发人 ...
- Atitit.加密算法ati Aes的框架设计
Atitit.加密算法ati Aes的框架设计 版本进化 c:\1t\aesC47.java c:\1t\aes.java 增加了public static byte[] encrypt(byte[] ...
- HTTP慢速DOS(slow http denial of service attack)
0x00用途 DOS攻击测试 0x01原理 传送门: http://blog.csdn.net/meiru8/article/details/38726025 https://www.nigesb.c ...
- 渗透测试-奇技淫巧(一)--源IP地址隐藏
切记,切记.本文只作为技术交流,提醒各位注意网络安全,请勿用于其它用途,否则后果自付. 在很多时候,某某不希望不愿意有人溯源他的地址.他们是如何隐藏IP的? 今天来浅析下,如何隐藏源地址. 用到的工具 ...
- “不要抄代码!自己的代码也不要抄!”
在 Adventure 位于深圳的电子设备组装厂(SZE)里,小朱狠狠的对自己说. 他刚刚在调试 STM32F407VG 的 SPI 功能.就在昨天,他刚刚调试好了 STM32F407VG 的 USA ...
- 联想A880 DIY 换触摸屏屏幕
今年初入手的Lenovo A880手机,由于摔坏了屏幕不过能正常显示,咨询了联想的售后,说触摸屏和显示屏是分离的,换触摸屏需要280左右 为发挥DIY的精神,准备自己来处理这个屏幕 第一步:购买屏幕, ...
- [DOM Event Learning] Section 3 jQuery事件处理基础 on(), off()和one()方法使用
[DOM Event Learning] Section 3 jQuery事件处理基础 on(),off()和one()方法使用 jQuery提供了简单的方法来向选择器(对应页面上的元素)绑定事件 ...
- windows下安装web服务器
有条件下还是在linux下部署.window上真心问题挺多的. 推荐安装Visual-NMP,轻量级.组件升级方面等. Nginx绑定IPv4和IPv6的方法 listen 80; listen [: ...
- Ignite China 2015 之行
微软首届Ignite China选择了金秋十月的北京,在顺义的九华山庄举办.这几天北京的空气特别好,再加上郊区高楼少,令人心胸开阔了不少.这次Ignite之行的任务有两个,其一是27号晚上与Windo ...