更新: 基本的に全会一致の反対意見で構成されたすべてのコメントに感謝します。提起されたすべての反論は有効でしたが、棺桶の最終的な釘は、最終的には、このアイデアが表面上提供したわずかな利点でさえ、定型コードの排除という事実によって無効にされたというアニの鋭い観察であったと思います。アイデア自体には、独自のボイラープレート コードが必要です。
ええ、私が確信していると考えてください。それは悪い考えです。
そして、私の尊厳をいくらか救うために:私は議論のためにそれを演じたかもしれませんが、そもそもこのアイデアに本当に納得したことはありませんでした. 本音。
この質問をばかげているとして却下する前に、次のことを検討してください。
IEnumerable<T>
from* を継承しますIEnumerable
。つまり、実装する型はIEnumerable<T>
一般にと(明示的に)の両方 を実装する必要があります。これは基本的に定型コードに相当します。IEnumerable<T>.GetEnumerator
IEnumerable.GetEnumerator
- そのメソッドがメソッドとプロパティを持つ何らかの型のオブジェクトを返す限り
foreach
、メソッドを持つ任意の型を上書きできます。したがって、型がシグネチャを持つ1 つのメソッドを定義している場合、 を使用してそれを列挙することは合法です。GetEnumerator
MoveNext
Current
public IEnumerator<T> GetEnumerator()
foreach
- 明らかに、インターフェイスを必要とする多くのコードがあり
IEnumerable<T>
ます。たとえば、基本的にすべての LINQ 拡張メソッドです。幸いなことに、C# がキーワードを介して提供する自動反復子生成を使用すると、可能な型からforeach
に移行するのは簡単です。IEnumerable<T>
yield
これをすべてまとめると、次のような独自のインターフェースを定義するとどうなるかというクレイジーなアイデアが浮かびました。
public interface IForEachable<T>
{
IEnumerator<T> GetEnumerator();
}
次に、列挙可能にしたい型を定義するたびに、 の代わりにこのインターフェイスを実装し、2 つのメソッド (1 つは明示的)IEnumerable<T>
を実装する必要がなくなります。GetEnumerator
例えば:
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().
}
最後に、この型をインターフェイスを必要とするコードと互換性を持たせるために、次のIEnumerable<T>
ように拡張メソッドを定義して、 anyIForEachable<T>
から anに移動することができますIEnumerable<T>
。
public static class ForEachableExtensions
{
public static IEnumerable<T> AsEnumerable<T>(this IForEachable<T> source)
{
foreach (T item in source)
{
yield return item;
}
}
}
これを行うことで、あらゆる方法で の実装として使用できる型を設計できるようになりますが、それぞれのIEnumerable<T>
厄介な明示的なIEnumerable.GetEnumerator
実装は必要ありません。
例えば:
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);
}
皆さんは、このアイデアについてどう思いますか? これが間違いである理由を見逃していますか?
最初はそれほど大したことではないものの、おそらく非常に複雑なソリューションのように思えることを私は認識しています(インターフェースを明示的に定義する必要があることを本当に気にかけている人はいないと思いIEnumerable
ます)。しかし、それは頭に浮かんだだけで、このアプローチがもたらす明らかな問題は見られません。
一般に、少量のコードを何度も書かなければならないという手間を省くために、適度な量のコードを 1 回書くことができれば、それだけの価値があります。
*それは使用する正しい用語ですか? あるインターフェイスが別のインターフェイスを「継承する」と言うのはいつも躊躇します。でも当たってるかも。