鸭在C#编译器中键入 [英] Duck typing in the C# compiler
问题描述
注意这是不是有关如何在C#中实现或模拟鸭式键入的问题...
几年来,我的印象是,某些C#语言特性是依赖于语言本身定义的数据结构(对我来说,这似乎是一个奇怪的鸡蛋和鸡蛋场景)。例如,我的印象是 foreach
循环只能用于实现 IEnumerable
的类型。 / p>
从那时起,我就明白C#编译器使用鸭式类型来确定一个对象是否可以在foreach循环中使用,查找 GetEnumerator
方法,而不是 IEnumerable
。这使得很有意义,因为它删除了鸡&
我有点困惑,为什么这不是似乎不是这样的情况与使用
block和 IDisposable
。有没有什么特别的原因编译器不能使用鸭类型&查找 Dispose
方法?
也许在IDisposable下面还有其他的事情发生?
em>讨论为什么有有一个没有实现IDisposable的Dispose方法的对象不在此问题的范围之内:)
在C#2之前,在 foreach
上使用此鸭类型只是可以实现一个强类型的迭代器,也是在没有装箱的情况下迭代值类型的唯一方法。我可疑如果C#和.NET有泛型开头, foreach
会有必需 IEnumerable< T>
,而不是鸭子类型。
现在编译器使用这种鸭类型其他地方我可以想到:
- 集合初始化器寻找一个合适的
Add
overload (以及类型必须实现IEnumerable
,只是为了表明它真的是某种类型的集合);这允许灵活添加单个项目,键/值对等。 - LINQ(
选择
等) - 这是LINQ如何实现而不必更改IEnumerable< T>
本身 - C#5等待表达式require
GetAwaiter
返回一个awaiter类型,它具有IsCompleted
/OnCompleted
/GetResult
在这两种情况下,
由于 IDisposable
已经存在,框架自第一个版本,我不认为有任何好处在鸭类型使用
语句。我知道你明确试图在讨论中不实现 IDisposable
而优惠 Dispose
的原因,但我认为这是一个要害。需要有良好的理由在语言中实现一个特性,我认为鸭式打字是一个支持已知接口的功能。如果这样做没有明显的好处,它将不会以语言结束。
Note This is not a question about how to implement or emulate duck typing in C#...
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
.
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.
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?
Perhaps there's something else going on under the hood with IDisposable?
Discussing why you would ever have an object with a Dispose method that didn't implement IDisposable is outside the scope of this question :)
There's nothing special about IDisposable
here - but there is something special about iterators.
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:
- 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.
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#编译器中键入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!