惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
N
Netflix TechBlog - Medium
The Register - Security
The Register - Security
C
Cybersecurity and Infrastructure Security Agency CISA
H
Hackread – Cybersecurity News, Data Breaches, AI and More
The Hacker News
The Hacker News
P
Proofpoint News Feed
Project Zero
Project Zero
The GitHub Blog
The GitHub Blog
The Last Watchdog
The Last Watchdog
F
Fortinet All Blogs
S
Schneier on Security
Help Net Security
Help Net Security
Security Archives - TechRepublic
Security Archives - TechRepublic
C
Check Point Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
P
Proofpoint News Feed
I
InfoQ
T
The Blog of Author Tim Ferriss
Cisco Talos Blog
Cisco Talos Blog
Stack Overflow Blog
Stack Overflow Blog
T
Troy Hunt's Blog
人人都是产品经理
人人都是产品经理
T
Threatpost
www.infosecurity-magazine.com
www.infosecurity-magazine.com
C
Cyber Attacks, Cyber Crime and Cyber Security
雷峰网
雷峰网
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
爱范儿
爱范儿
Forbes - Security
Forbes - Security
Vercel News
Vercel News
S
Security Affairs
美团技术团队
P
Privacy & Cybersecurity Law Blog
N
News and Events Feed by Topic
Cyberwarzone
Cyberwarzone
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Jina AI
Jina AI
Spread Privacy
Spread Privacy
Attack and Defense Labs
Attack and Defense Labs
IT之家
IT之家
U
Unit 42
Recorded Future
Recorded Future
W
WeLiveSecurity
PCI Perspectives
PCI Perspectives
P
Palo Alto Networks Blog
H
Hacker News: Front Page
S
Security @ Cisco Blogs
博客园 - 【当耐特】

博客园 - Zhenway

Azure SignalR支持replication啦 Azure SignalR总览 定制json序列化 今天折腾这么一个正则 docfx组件介绍--YamlSerialization docfx daylybuild docfx开源啦 docfx组件介绍--MarkdownLite docfx预热中 合并批量请求 一个简单的Linq to TreeNode 在finally中调用一个需要await的方法 4.5你太黑了,不带这么玩TypeForwardedTo的 一个非常简单的反射加速方案 加载时预防并发执行 又发现一个msdn的坑 又发现个.net framework的坑 sql server死锁神器 踩到一个Emit的坑,留个纪念
当泛型方法推断,扩展方法遇到泛型类型in/out时。。。
Zhenway · 2014-05-19 · via 博客园 - Zhenway

  说到泛型方法,这个是.net 2.0的时候引入的一个重要功能,c#2.0也对此作了非常好的支持,可以不需要显试的声明泛型类型,让编译器自动推断,例如:

1 void F<T>(T value){}
2 //...
3 int i = 0;
4 F(i);

此时,编译器可以自动推导出这里的T就是int,这极大的方便了我们写代码的效率。

  说到扩展方法,这个是.net 3.5的时候引入的另一个重要功能,c#3.0也在linq中大量的应用这个功能,当扩展方法是扩展一个泛型的类型时,显然也不需要我们指定具体的泛型类型,编译器会为我们自动推断,例如:

1 static void F<T>(this List<T> list){}
2 //...
3 List<int> list = new List<int>();
4 list.F();

  最后说到协变和逆变(也就是c#中的in/out),这个是.net 4.0的时候引入的一个重要的功能,例如:

1 Func<string> foo = () => "Foo";
2 Func<object> bar = foo;

  然后,我们将泛型方法推断和协变和逆变放在一起:

1 public static void Foo(this Action<string> action){}
2 //...
3 Action<object> action = o => {};
4 action.Foo();

  看起来很不错,不过要是遇到些复杂点的会怎么样?

1 public static void Foo(this IEnumerable<IEnumerable<object>> that) {}
2 //...
3 List<List<string>> bar = new List<List<string>>();
4 bar.Foo();

  看到这里相信所有都为c#的in/out拍手叫好,不过别急,除了out+out我们还可以玩令人抓狂的in+in:

1 public static void Foo(this Action<Action<object>> that) {}
2 //...
3 Action<Action<string>> action = a => a("O_O");
4 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#的无比赞美了吧,不过,重点是这里,别忘了,多个泛型参数可以玩出很多猥琐的东西,例如,双/多泛型锁定(随便起的名字):

1 public static void Foo<T>(this Action<T, T> that) {}
2 //...
3 Action<string, object> action = (s, o) => {};
4 action.Foo();

  c#编译器对扩展方法支持的确是有一手,这么变态的T也可以被推断出是object,不得不佩服一把,再来看看out的情况(别忘了前面的结论in+in=>out):

1 public static void Foo<T>(this Action<Action<T>, Action<T>> that) {}
2 //...
3 Action<Action<string, object>> action = (s, o) => {};
4 action.Foo();

  c#编译器依然表现出专业的结果,正确的推断出了T应当是string,不过,泛型方法的类型推断却完全是另外一番风景:

1 public void Foo<T>(Action<T, T> that) {}
2 //...
3 Action<string, object> action = (s, o) => {};
4 Foo(action); // failed.
5 Foo<object>(action); // failed.
6 Foo((Action<object, object>)action); // succeeded.

  看到这个结果是不是想大骂c#编译器:这也太山寨了吧。

  别急,我们还可以玩得更加浮云:

1 public static Foo<T>(this Action<Action<T>, Action<T>> that) {}
2 // ...
3 Action<Action<List<string>>, Action<ArrayList>> bar = null;
4 bar.Foo(); // failed.
5 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的具体类型。