66

これは、C#でダックタイピングを実装またはエミュレートする方法についての質問ではありません...

数年の間、特定のC#言語機能は、言語自体で定義されたデータ構造に依存しているという印象を受けました(これは、私には常に奇妙な鶏と卵のシナリオのように見えました)。たとえば、foreachループはを実装した型でのみ使用できるという印象を受けましたIEnumerable

GetEnumeratorそれ以来、C#コンパイラはダックタイピングを使用して、オブジェクトがforeachループで使用できるかどうかを判断し、ではなくメソッドを探すことを理解するようになりましたIEnumerable。これは、鶏肉と卵の難問を取り除くので、非常に理にかなっています。

usingなぜこれがブロックとの場合ではないように思われるのかについて、私は少し混乱していIDisposableます。Disposeコンパイラがダックタイピングを使用してメソッドを探すことができない特別な理由はありますか?この不一致の理由は何ですか?

おそらく、IDisposableの内部で何か他のことが起こっているのでしょうか?

IDisposableを実装していないDisposeメソッドを持つオブジェクトがある理由を説明することは、この質問の範囲外です:)

4

3 に答える 3

44

IDisposableここには特別なこと何もありませんが、イテレータには特別なことがあります。

C#2以前は、このダックタイプを使用することforeach唯一の方法であり、厳密に型指定されたイテレータを実装でき、ボックス化せずに値型を反復処理する唯一の方法でもありました。C#と.NETに最初からジェネリックがあったとしたらforeach、代わりに必要 IEnumerable<T>であり、ダックタイピングがなかったのではないかと思います。

現在、コンパイラは、私が考えることができる他のいくつかの場所でこの種のダックタイピングを使用しています。

  • コレクション初期化子は、適切なオーバーロードを探します(また、それが実際に何らかのコレクションであることを示すために、Add実装する必要のあるタイプも探します)。IEnumerableこれにより、単一のアイテム、キーと値のペアなどを柔軟に追加できます。
  • LINQ(など)-これは、LINQがその柔軟性を実現する方法であり、それ自体Selectを変更することなく、複数の型に対して同じクエリ式形式を可能にしますIEnumerable<T>
  • C#5のawait式では、//を持つawaiter型を返す必要がGetAwaiterあります。IsCompletedOnCompletedGetResult

どちらの場合も、これにより、以前は概念が存在しなかった既存のタイプとインターフェースに機能を簡単に追加できます。

それが最初のバージョンからフレームワークに含まれていることを考えると、ダックタイピングでステートメントをIDisposable入力してもメリットはないと思います。議論から実装せずusingに持っている理由を明確に割り引いてみたのは知っていますが、それは重要なポイントだと思います。この言語で機能を実装するのには十分な理由が必要です。ダックタイピングは、既知のインターフェイスをサポートする以上の機能であると私は主張します。そうすることに明確な利点がない場合、それはその言語で終わることはありません。DisposeIDisposable

于 2011-06-16T08:24:57.490 に答える
15

鶏が先か卵が先か: に依存しないので依存する可能foreach性があります。実装されていないコレクションでforeachが許可される理由は、おそらく主に歴史的なものです。IEnumerableIEnumerableforeachIEnumerable

C#では、foreachとの互換性を保つために、コレクションクラスがIEnumerableおよびIEnumeratorから継承する必要は厳密にはありません。クラスに必要なGetEnumerator、MoveNext、Reset、およびCurrentメンバーがある限り、foreachで機能します。インターフェイスを省略すると、Currentの戻り型をオブジェクトよりも具体的に定義できるという利点があり、それによって型の安全性が提供されます。

さらに、すべての鶏が先か卵が先かという問題が実際に問題になるわけではありません。たとえば、関数がそれ自体を呼び出すことができる(再帰!)か、参照型がそれ自体を含むことができます(リンクリストのように)。

それで、using彼らが簡単に言うことができるのに、なぜ彼らはダックタイピングとして指定するのにトリッキーなものを使用するのでしょうIDisposableか?基本的に、ダックタイピングを使用すると、型システムの周りでエンドランを実行します。これは、型システムが問題に対処するには不十分(または非実用的)な場合にのみ役立ちます。

于 2011-06-16T08:24:56.643 に答える
0

あなたが尋ねている質問は、鶏が先か卵が先かという状況ではありません。言語コンパイラの実装方法に似ています。C#とVB.NETコンパイラのように、実装方法が異なります。helloworldの単純なコードを記述し、コンパイラの両方でコンパイルしてILコードを検査すると、それらは異なります。あなたの質問に戻って、私はどのILコードがC#コンパイラによって生成されるかを説明したいと思いますIEnumerable

IEnumerator e = arr.GetEnumerator();

while(e.MoveNext())
{
   e.Currrent;
}

そのため、C#コンパイラは。の場合に合わせて調整されていforeachます。

于 2011-06-16T08:44:17.427 に答える