问题描述
更新:我AP preciate所有的意见,已基本包括一致反对的。虽然提出的每异议是有效的,我觉得在棺材最终钉子是Ani's敏锐的观察,归根结底,甚至在一个 微乎其微的利益,这种想法表面上提供的 - 消除样板code - 是否定的其实这种想法本身就需要它的的的样板code。
Update: I appreciate all of the comments, which have essentially comprised unanimous opposition. While every objection raised was valid, I feel that the ultimate nail in the coffin was Ani's astute observation that, ultimately, even the one miniscule benefit that this idea ostensibly offered -- the elimination of boilerplate code -- was negated by the fact that the idea itself would require its own boilerplate code.
所以呀,把我坚信:这将是一个坏主意。
So yeah, consider me convinced: it would be a bad idea.
而只是为了挽救自己的尊严有点:我可能发挥它的参数的缘故,但我从来没有真正对这个想法销往开始 - 只是好奇,想听听别人不得不说一下吧。诚实的。
And just to sort of salvage my dignity somewhat: I might have played it up for argument's sake, but I was never really sold on this idea to begin with -- merely curious to hear what others had to say about it. Honest.
在您关闭这个问题是荒谬的,我问你要考虑以下几点:
Before you dismiss this question as absurd, I ask you to consider the following:
-
的IEnumerable< T>
从继承*的IEnumerable
,这意味着任何类型的实现的IEnumerable< T>
一般必须实施两个的IEnumerable< T> .GetEnumerator
的和的(明确)IEnumerable.GetEnumerator
。这基本上相当于样板code。 - 您可以
的foreach
的任何类型,有一个的GetEnumerator
的方法,只要该方法返回一个对象某种类型与的MoveNext
方法和当前
属性。所以,如果你的类型定义的一个方法签名公开的IEnumerator< T>的GetEnumerator()
,这是合法的使用,以枚举它的foreach
。 - 显然,有很多code,在那里,需要
的IEnumerable< T>
界面 - 例如,基本上所有的LINQ扩展方法。幸运的是,从一种类型,你可以的foreach
在去一个的IEnumerable< T>
是微不足道的使用自动迭代器一代C#通过产量用品
关键字。
IEnumerable<T>
inherits from*IEnumerable
, which means that any type that implementsIEnumerable<T>
generally must implement bothIEnumerable<T>.GetEnumerator
and (explicitly)IEnumerable.GetEnumerator
. This basically amounts to boilerplate code.- You can
foreach
over any type that has aGetEnumerator
method, as long as that method returns an object of some type with aMoveNext
method and aCurrent
property. So if your type defines one method with the signaturepublic IEnumerator<T> GetEnumerator()
, it's legal to enumerate over it usingforeach
. - Clearly, there is a lot of code out there that requires the
IEnumerable<T>
interface -- for instance, basically all of the LINQ extension methods. Luckily, to go from a type that you canforeach
on to anIEnumerable<T>
is trivial using the automatic iterator generation that C# supplies via theyield
keyword.
那么,把这个都在一起,我有这个疯狂的想法:如果我只是定义自己的界面,如下所示:
So, putting this all together, I had this crazy idea: what if I just define my own interface that looks like this:
public interface IForEachable<T>
{
IEnumerator<T> GetEnumerator();
}
然后每当我定义我想成为枚举类型,我实施的这个的接口,而不是的IEnumerable&LT; T&GT;
,省去了实现两个的GetEnumerator
方法(一个明确的)。例如:
Then whenever I define a type that I want to be enumerable, I implement this interface instead of IEnumerable<T>
, eliminating the need to implement two GetEnumerator
methods (one explicit). For example:
class NaturalNumbers : IForEachable<int>
{
public IEnumerator<int> GetEnumerator()
{
int i = 1;
while (i < int.MaxValue)
{
yield return (i++);
}
}
// Notice how I don't have to define a method like
// IEnumerator IEnumerable.GetEnumerator().
}
最后,为了使这种类型与code兼容的的确实的期望的IEnumerable&LT; T&GT;
接口,我可以定义一个扩展方法,从任何 IForEachable&LT去; T&GT;
到的IEnumerable&LT; T&GT;
像这样:
Finally, in order to make this type compatible with code that does expect the IEnumerable<T>
interface, I can just define an extension method to go from any IForEachable<T>
to an IEnumerable<T>
like so:
public static class ForEachableExtensions
{
public static IEnumerable<T> AsEnumerable<T>(this IForEachable<T> source)
{
foreach (T item in source)
{
yield return item;
}
}
}
在我看来,这样做使我的设计是在各方面都为的实现IEnumerable的&LT可用的类型; T&GT;
,但没有那个讨厌的明确 IEnumerable.GetEnumerator
在每一个实现。
It seems to me that doing this enables me to design types that are usable in every way as implementations of IEnumerable<T>
, but without that pesky explicit IEnumerable.GetEnumerator
implementation in each one.
例如:
var numbers = new NaturalNumbers();
// I can foreach myself...
foreach (int x in numbers)
{
if (x > 100)
break;
if (x % 2 != 0)
continue;
Console.WriteLine(x);
}
// Or I can treat this object as an IEnumerable<T> implementation
// if I want to...
var evenNumbers = from x in numbers.AsEnumerable()
where x % 2 == 0
select x;
foreach (int x in evenNumbers.TakeWhile(i => i <= 100))
{
Console.WriteLine(x);
}
你是什么人想到这个主意的?我缺少一些原因,这将是一个错误?
What do you guys think of this idea? Am I missing some reason why this would be a mistake?
我知道这可能看起来像一个过于复杂的解决方案,以什么不是什么大不了的事,开始与(我怀疑任何人的真正的关心,大约有明确定义的<$ C多$ C>的IEnumerable 接口);但它只是突然出现在我的头,我没有看到任何明显的问题,这种做法将构成。
I realize it probably seems like an overly complex solution to what isn't that big of a deal to start with (I doubt anybody really cares that much about having to explicitly define the IEnumerable
interface); but it just popped into my head and I'm not seeing any obvious problems that this approach would pose.
在一般情况下,如果我能写的code的适量一旦的保存自己不必编写少量的code的很多次的麻烦的,对我来说,这是值得的。
In general, if I can write a moderate amount of code once to save myself the trouble of having to write a small amount of code lots of times, to me, it's worth it.
*那是正确的术语来使用?我总是犹豫不决,从继承另一个说一个接口,因为这似乎并不正确捕获它们之间的关系。但也许这是正确的。
推荐答案
你不只是移动的样板别处 - 从写 IEnumerable.GetEnumerator
方法上的每个类调用你的 AsEnumerable
延长每次的IEnumerable&LT; T&GT;
预期?通常情况下,我预计要使用的枚举类型查询远远更多的时间比它被写入(这正是一次)。这意味着这种模式将导致的更多的样板,平均。
Aren't you just moving the boilerplate somewhere else - from writing the IEnumerable.GetEnumerator
method on each class to calling your AsEnumerable
extension every time an IEnumerable<T>
is expected? Typically, I would expect an enumerable type to be used for querying far more times than it is written (which is exactly once). This would mean that this pattern will lead to more boilerplate, on average.
这篇关于为什么要实现IEnumerable(T),如果我可以定义一个GetEnumerator的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!