问题描述
注意这不是关于如何在 C# 中实现或模拟鸭子类型的问题...
Note This is not a question about how to implement or emulate duck typing in C#...
多年来,我的印象是某些 C# 语言特性依赖于语言本身定义的数据结构(在我看来,这总是一种奇怪的鸡与蛋的场景).例如,我的印象是 foreach
循环只能用于实现 IEnumerable
的类型.
For several years I was under the impression that certain C# language features were depdendent on data structures defined in the language itself (which always seemed like an odd chicken & egg scenario to me). For example, I was under the impression that the foreach
loop was only available to use with types that implemented IEnumerable
.
从那以后我开始明白 C# 编译器使用鸭子类型来确定一个对象是否可以在 foreach 循环中使用,寻找 GetEnumerator
方法而不是 IEnumerable代码>.这很有意义,因为它可以去除鸡肉和鸡蛋难题.
Since then I've come to understand that the C# compiler uses duck typing to determine whether an object can be used in a foreach loop, looking for a GetEnumerator
method rather than IEnumerable
. This makes a lot of sense as it removes the chicken & egg conundrum.
我有点困惑,为什么 using
块和 IDisposable
似乎不是这种情况.编译器是否有任何特殊原因不能使用鸭子类型 &寻找 Dispose
方法?这种不一致的原因是什么?
I'm a little confused as to why this isn't doesn't seem to be the case with the using
block and IDisposable
. Is there any particular reason the compiler can't use duck typing & look for a Dispose
method? What's the reason for this inconsistency?
也许 IDisposable 的幕后还有其他事情发生?
Perhaps there's something else going on under the hood with IDisposable?
讨论为什么您会永远拥有一个带有未实现 IDisposable 的 Dispose 方法的对象,这超出了这个问题的范围:)
Discussing why you would ever have an object with a Dispose method that didn't implement IDisposable is outside the scope of this question :)
推荐答案
这里的 IDisposable
没有什么特别之处 - 但迭代器有一些特别之处.
There's nothing special about IDisposable
here - but there is something special about iterators.
在 C# 2 之前,在 foreach
上使用这种鸭子类型是 only 是您可以实现强类型迭代器的唯一方法,也是迭代值类型的唯一方法没有拳击.我怀疑如果 C# 和 .NET 有泛型开始,foreach
将有 required IEnumerable<T>
相反,没有鸭子打字.
Before C# 2, using this duck type on foreach
was the only was you could implement a strongly-typed iterator, and also the only way of iterating over value types without boxing. I suspect that if C# and .NET had had generics to start with, foreach
would have required IEnumerable<T>
instead, and not had the duck typing.
现在编译器在我能想到的其他几个地方使用了这种鸭子类型:
Now the compiler uses this sort of duck typing in a couple of other places I can think of:
- 集合初始化器寻找合适的
Add
重载(以及必须实现IEnumerable
的类型,只是为了表明它确实是某种集合);这允许灵活添加单个项目、键/值对等 - LINQ (
Select
等) - 这就是 LINQ 实现其灵活性的方式,允许针对多种类型使用相同的查询表达式格式,而无需更改IEnumerable<T>
本身 - C# 5 await 表达式要求
GetAwaiter
返回具有IsCompleted
/OnCompleted
/GetResult
的 awaiter 类型
- Collection initializers look for a suitable
Add
overload (as well as the type having to implementIEnumerable
, just to show that it really is a collection of some kind); this allows for flexible adding of single items, key/value pairs etc - LINQ (
Select
etc) - this is how LINQ achieves its flexibility, allowing the same query expression format against multiple types, without having to changeIEnumerable<T>
itself - The C# 5 await expressions require
GetAwaiter
to return an awaiter type which hasIsCompleted
/OnCompleted
/GetResult
在这两种情况下,都可以更轻松地将功能添加到现有类型和接口中,而这个概念之前并不存在.
In both cases this makes it easier to add the feature to existing types and interfaces, where the concept didn't exist earlier on.
鉴于 IDisposable
自第一个版本以来一直在框架中,我认为鸭子键入 using
语句没有任何好处.我知道您在讨论中明确试图打折使用 Dispose
而不实现 IDisposable
的原因,但我认为这是一个关键点.在语言中实现一个特性需要有充分的理由,我认为鸭子类型是一个超越支持已知接口的特性.如果这样做没有明显的好处,它就不会出现在语言中.
Given that IDisposable
has been in the framework since the very first version, I don't think there would be any benefit in duck typing the using
statement. I know you explicitly tried to discount the reasons for having Dispose
without implementing IDisposable
from the discussion, but I think it's a crucial point. There need to be good reasons to implement a feature in the language, and I would argue that duck typing is a feature above-and-beyond supporting a known interface. If there's no clear benefit in doing so, it won't end up in the language.
这篇关于在 C# 编译器中输入鸭子的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!