In C # tauchten all diese magischen Methoden auf, ohne von einer Schnittstelle gesichert zu werden. Warum wurde das gewählt?
Lassen Sie mich erklären.
Wenn in C # zuvor ein Objekt die IEnumerable
Schnittstelle implementiert hatte , konnte es automatisch von einer foreach
Schleife durchlaufen werden . Das macht für mich Sinn, da es durch eine Schnittstelle gesichert ist und wenn ich meine eigene Iterator
Funktion innerhalb der Klasse hätte, die durchlaufen wird, könnte ich das tun, ohne mir Sorgen zu machen, dass es auf magische Weise etwas anderes bedeuten würde.
Nun, anscheinend (nicht sicher wann), werden diese Schnittstellen nicht mehr benötigt. Es müssen nur die richtigen Namenskonvertierungen vorhanden sein.
Ein weiteres Beispiel besteht darin, ein Objekt durch eine Methode mit einem genauen Namen zu warten , GetAwaiter
die einige bestimmte Eigenschaften aufweist.
Warum nicht eine Schnittstelle erstellen, wie sie es mit dieser "Magie" gemacht hat IEnumerable
oder INotifyPropertyChanged
um sie statisch zu sichern?
Weitere Details zu dem, was ich hier meine:
http://blog.nem.ec/2014/01/01/magic-methods-c-sharp/
Was sind die Vor- und Nachteile magischer Methoden? Gibt es irgendwo im Internet etwas darüber, warum diese Entscheidungen getroffen wurden?
async
/ benötigen,await
funktioniert dies nur mit Code, der geschrieben wurde, nachdem .NET 4.5 weit genug verbreitet wurde, um ein brauchbares Ziel zu sein. Dies ist im Grunde genommen jetzt der Fall. Aber eine rein syntaktische Übersetzung in Methodenaufrufe ermöglicht es mirawait
, vorhandene Typen nachträglich zu erweitern.foreach
anfangs als Basisfunktionalität für eine Schleife implementiert . Es nie wurde für das Objekt eine Anforderung zur UmsetzungIEnumerable
fürforeach
zu arbeiten. Es war nur eine Konvention, dies zu tun.Antworten:
Im Allgemeinen werden "magische Methoden" verwendet, wenn es nicht möglich ist, eine Schnittstelle zu erstellen, die auf die gleiche Weise funktioniert.
Als
foreach
es zum ersten Mal in C # 1.0 eingeführt wurde (dieses Verhalten ist sicherlich nichts Neues), musste es magische Methoden verwenden, da es keine Generika gab. Die Optionen waren im Grunde:Verwenden Sie das nicht-generische
IEnumerable
undIEnumerator
das funktioniert mitobject
s, was Boxing-Werttypen bedeutet. Da die Iteration einer Liste vonint
s sehr schnell sein sollte und auf keinen Fall viele Werte in Garbage Boxes erzeugen sollte, ist dies keine gute Wahl.Warten Sie auf Generika. Dies würde wahrscheinlich bedeuten, .Net 1.0 (oder zumindest
foreach
) um mehr als 3 Jahre zu verzögern .Wende magische Methoden an.
Sie entschieden sich also für Option 3 und diese blieb aus Gründen der Abwärtskompatibilität bei uns, obwohl dies seit .NET 2.0
IEnumerable<T>
auch funktioniert hätte.Auflistungsinitialisierer können für jeden Auflistungstyp unterschiedlich aussehen. Vergleichen Sie
List<T>
:und
Dictionary<TKey, TValue>
:Es kann keine einzige Schnittstelle geben, die nur das erste Formular
List<T>
und nur das zweite Formular unterstütztDictionary<TKey, TValue>
.LINQ-Methoden werden in der Regel als Erweiterungsmethoden implementiert (sodass es für alle implementierenden Typen nur eine einzige Implementierung von z. B. LINQ to Object geben kann), sodass
IEnumerable<T>
keine Schnittstelle verwendet werden kann.Für
await
die,GetResult()
Methode zurückgeben kann entwedervoid
oder irgendeine ArtT
. Auch hier kann es keine einzige Schnittstelle geben, die beide Funktionen unterstützt. Obwohlawait
teilweise schnittstellenbasiert: Der Kellner muss implementierenINotifyCompletion
und kann auch implementierenICriticalNotifyCompletion
.quelle
foreach
C # 1.2 (in MSDN für C # 1.0 gibt es nichts) heißt es, dass der Ausdruck inforeach
"WertetIEnumerable
einen Typ aus, der eineGetEnumerator
Methode implementiert oder deklariert ". Und ich bin nicht sicher, was Sie damit meinen, Unboxing in C # ist immer explizit.foreach(T x in sequence)
wendet explizite CastsT
auf die Elemente der Sequenz an. Wenn die Sequenz eine einfache SequenzIEnumerable
undT
ein Werttyp ist, wird sie entpackt, ohne dass eine explizite Umwandlung in Ihren Code geschrieben wird. Einer der hässlicheren Teile von C #.foreach
.)