マジックメソッドがC#で実装されたのはなぜですか?


16

C#では、インターフェイスによってバックアップされることなく、これらすべての魔法のメソッドがポップアップ表示されるようになりました。なぜこれが選ばれたのですか?

説明させてください。

以前のC#では、オブジェクトがIEnumerableインターフェイスを実装すると、foreachループによって自動的に反復可能になりました。インターフェースによってバックアップされているため、それは理にかなっています。Iterator繰り返し処理されるクラス内に独自の関数がある場合、魔法のように何かを意味することを心配せずにそれを行うことができます。

今、どうやら(いつかはわからないが)、これらのインターフェースはもはや必要ではない。正しい命名変換が必要なだけです。

別の例は、いくつかの特定のプロパティを持つ正確 な名前のメソッドを持つことにより、オブジェクトを待機可能にすることGetAwaiterです。

この「マジック」を静的にバックアップしIEnumerableたりINotifyPropertyChanged、静的にバックアップしたりするようなインターフェースを作成してみませんか?

ここでの意味の詳細:

http://blog.nem.ec/2014/01/01/magic-methods-c-sharp/

魔法の手法の長所と短所は何ですか?また、これらの決定が行われた理由について何かを見つけることができるオンラインの場所はどこにありますか?


4
閉じたくない場合は、「魔法が悪い」理由について個人的な意見を編集する必要があります。
ダグ14

2
Anders Hejlsbergがなぜそうしたのかを知りたい場合は、彼に尋ねる必要があります。なぜそうしたのかを伝えることができるだけであり、これは前方互換性のためです。拡張メソッドを使用すると、既存のタイプにメソッドを「偽造」できますが、拡張インターフェースはありません。たとえば、async/のインターフェイスが必要な場合、await.NET 4.5が実行可能なターゲットとなるのに十分な規模になった後に作成されたコードでのみ機能します。しかし、メソッド呼び出しへの純粋な構文変換によりawait、事後に既存の型に機能を追加することができます。
ヨルグWミットタグ

2
これは基本的にオブジェクト指向に適用されることに注意してください。オブジェクトが適切なメッセージに応答する限り、それは正しいタイプであると見なされます。
ヨルグWミットタグ

7
「以前」と「現在」は後方にあります-マジックメソッドはforeach、最初のループバックの基本機能として実装されました。オブジェクトが機能するために実装する必要はありませんでした。そうするのは慣例に過ぎません。IEnumerableforeach
ジェシーC.スライサー

2
私からアイデアを得て思い出すところ、この@gbulmerです:blogs.msdn.com/b/ericlippert/archive/2011/06/30/...(およびより少ない程度にericlippert.com/2013/07/22/...
ジェシーC.スライサー

回答:


16

一般に、「マジックメソッド」は、同じように機能するインターフェイスを作成できない場合に使用されます。

foreachC#1.0で最初に導入されたとき(その動作は確かに最近のものではありません)、ジェネリックがないため、マジックメソッドを使用する必要がありました。オプションは基本的に次のとおりです。

  1. 非ジェネリックIEnumerableを使用し、それはsでIEnumerator機能しobjectます。これは、値型のボクシングを意味します。intsのリストのようなものを繰り返し処理するのは非常に高速で、ゴミ箱に入れられた値を大量に作成するべきではないため、これは良い選択ではありません。

  2. ジェネリックを待ちます。これは、おそらく.Net 1.0(または少なくともforeach)を3年以上遅らせることを意味します。

  3. マジックメソッドを使用します。

したがって、彼らはオプション#3を選択しました。下位互換性の理由で、.Net 2.0以降、要求IEnumerable<T>も機能していましたが、それはそのままでした。


コレクション初期化子は、コレクションのタイプごとに異なるように見えます。比較するList<T>

public void Add(T item)

およびDictionary<TKey, TValue>

public void Add(TKey key, TValue value)

の最初のフォームList<T>と2番目のフォームのみをサポートする単一のインターフェースを持つことはできませんDictionary<TKey, TValue>


LINQメソッドは通常、拡張メソッドとして実装されるため(たとえばIEnumerable<T>、を実装するすべての型に対してLINQ to Objectの単一の実装が存在するようになります)、つまり、インターフェイスを使用することはできません。


の場合awaitGetResult()メソッドはいずれvoidかのタイプまたは何らかのタイプを返すことができますT。繰り返しますが、両方を処理できる単一のインターフェースを持つことはできません。けれどもはawait、部分的にインターフェイスベースである:awaiterは、実装する必要がありINotifyCompletion、また、実装することができますICriticalNotifyCompletion


1
C#1.0の「オプション#3を選択しました」と確信していますか?私の記憶はオプション1でした。私の記憶は、C#コンパイラが「自動ボックス化」と「自動ボックス化解除」を行ったため、Javaよりもかなり優れていると主張したことです。その理由の一部は、C#がforeachのようなコードをJavaよりもはるかに優れたものにしたと主張したことです。
gbulmer

1
foreachC#1.2 のドキュメント(C#1.0のMSDNには何もありません)には、foreach「実装IEnumerableする型またはGetEnumeratorメソッドを宣言する型に評価する」という表現が記載されています。 C#では常に明示的です。
svick 14

1
@gbulmerまた、2001年12月のC#のECMA仕様(C#1.0を意味する)は、次のようにも述べています(§15.8.4)。または、次の基準をすべて満たすことで収集パターンを実装します[…]」。
svick 14

1
@svick foreach(T x in sequence)T、シーケンスの要素に明示的なキャストを適用します。したがって、シーケンスがプレーンIEnumerableT値型である場合、明示的なキャストがコードに書き込まれることなくボックス化解除されます。C#のい部分の1つ。
CodesInChaos

@CodesInChaos「自動ボックス化解除」はかなり一般的に聞こえますが、この特定の機能を参照していることに気付きませんでした。(私たちが話していたので、私は持っているべきだと思いforeachます。)
svick 14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.