Delegieren als erster Parameter einer Erweiterungsmethode

8

Damen und Herren,

Ich habe vor kurzem dieses Experiment versucht:

%Vor%

Ich frage mich zwei Dinge:

  • Warum kann der Compiler den Parametertyp "int" nicht ableiten?

  • Verstehe ich richtig, dass Erweiterungsmethoden nicht auf Delegattypen erkannt werden, da ich denke, dass sie nicht wirklich von diesem Typ sind (aber eine "Methode" sind), die nur mit der Delegiertensignatur übereinstimmen? So löst ein solcher Wurf das. Wäre es nicht möglich, Szenario 1 zu aktivieren (nicht dieses natürlich, aber im Allgemeinen)? Ich schätze aus einer Sprache / Compiler-Perspektive und wäre es wirklich nützlich, oder versuche ich (wild), die Dinge hier wild zu missbrauchen?

Ich freue mich auf einige Einsichten. Thnx

    
chrisaut 31.05.2011, 13:02
quelle

3 Antworten

18

Sie haben hier eine Reihe von Fragen. (In der Zukunft würde ich empfehlen, wenn Sie mehrere Fragen haben, teilen Sie sie in mehrere Fragen und nicht in einen Beitrag mit mehreren Fragen auf; Sie erhalten wahrscheinlich bessere Antworten.)

  

Warum kann der Compiler den Parametertyp "int" nicht in:

ableiten?
%Vor%

Gute Frage. Anstatt hier zu antworten, verweise ich Sie auf meinen Artikel von 2007, der erklärt, warum dies in C # 3.0 nicht funktioniert hat:

Ссылка

Fazit: Grundsätzlich gibt es hier ein Henne-Ei-Problem. Wir müssen eine Überladungsauflösung auf int.TryParse durchführen, um zu bestimmen, welche Überladung von TryParse die beabsichtigte ist (oder, falls keine von ihnen funktioniert, was der Fehler ist). Die Überladungsauflösung versucht immer, aus Argumenten zu schließen. In diesem Fall versuchen wir genau auf die Art des Arguments zu schließen.

Wir könnten einen neuen Überladungsauflösungsalgorithmus entwickeln, der besagt: "Nun, wenn es nur eine Methode in der Methodengruppe gibt, dann wähle diese, selbst wenn wir nicht wissen, was die Argumente sind", aber das scheint schwach zu sein. Es scheint eine schlechte Idee für spezielle Fallgruppen zu sein, die nur eine Methode in sich haben, weil sie dann für das Hinzufügen neuer Überladungen bestraft werden; es kann plötzlich eine Bruchänderung sein.

Wie Sie den Kommentaren zu diesem Artikel entnehmen können, haben wir eine Menge gutes Feedback dazu bekommen. Die beste Rückmeldung war im Grunde genommen: "Nun, angenommen, die Typinferenz hat bereits die Typen aller Argumente herausgearbeitet und es ist der Rückgabetyp , den wir zu erschließen versuchen; In diesem Fall könnten Sie eine Überladungsauflösung machen. " Diese Analyse ist korrekt, und Änderungen an diesem Effekt gingen in C # 4. Ich habe darüber ein bisschen mehr gesprochen:

Ссылка

  

Verstehe ich richtig, dass Erweiterungsmethoden auf Delegattypen nicht erkannt werden, da ich denke, dass sie nicht wirklich von diesem Typ sind (aber eine "Methode" sind), die nur der Delegiertensignatur entsprechen?

Ihre Terminologie ist ein bisschen daneben, aber Ihre Idee ist richtig. Wir entdecken keine Erweiterungsmethoden, wenn der "Empfänger" eine Methodengruppe ist. Allgemeiner entdecken wir keine Erweiterungsmethoden, wenn der Empfänger einen Typ hat, der keinen eigenen Typ hat, sondern einen Typ annimmt, der auf seinem Kontext basiert: Methodengruppen, Lambdas, anonyme Methoden und das Null-Literal haben alle diese Eigenschaft. Es wäre wirklich seltsam, null.Whatever() zu sagen und eine Erweiterungs-Methode für String aufzurufen, oder noch seltsamer, (x=>x+1).Whatever() , und das hat eine Erweiterungs-Methode für Func<int, int> aufgerufen.

Die Zeile der Spezifikation, die dieses Verhalten beschreibt, lautet:

  

Eine implizite Identitäts-, Referenz- oder Boxenkonvertierung [muss existieren] von [dem Empfängerausdruck] zum Typ des ersten Parameters [...].

Conversions für Methodengruppen sind keine Identitäts-, Referenz- oder Boxenkonvertierungen. Sie sind Methodengruppen-Konvertierungen.

  

Wäre es nicht möglich, Szenario 1 zu aktivieren (nicht dieses natürlich, aber im Allgemeinen)? Ich schätze aus einer Sprache / Compiler-Perspektive und wäre es tatsächlich nützlich, oder versuche ich nur (wild), Dinge hier zu missbrauchen?

Es ist nicht undurchführbar . Wir haben hier ein ziemlich kluges Team und es gibt keinen theoretischen Grund, warum es so unmöglich ist. Es scheint uns einfach nicht wie eine Funktion zu sein, die der Sprache mehr Wert verleiht als die Kosten der zusätzlichen Komplexität.

Es gibt Zeiten, in denen es nützlich wäre. Zum Beispiel würde ich gerne in der Lage sein, dies zu tun; Angenommen, ich habe ein static Func<A, R> Memoize<A, R>(this Func<A, R> f) {...} :

%Vor%

Statt dessen, was Sie heute schreiben müssen, ist das:

%Vor%

Aber offen gesagt, die zusätzliche Komplexität, die das vorgeschlagene Merkmal der Sprache hinzufügt, wird nicht durch den kleinen Vorteil, dass der obige Code weniger ausführlich ist, bezahlt.

    
Eric Lippert 31.05.2011, 15:45
quelle
2

Der Grund für den ersten Fehler:
int.TryParse ist eine Methodengruppe, keine Objektinstanz eines beliebigen Typs. Erweiterungsmethoden können nur für Objektinstanzen aufgerufen werden. Aus diesem Grund ist der folgende Code ungültig:

%Vor%

Dies ist auch der Grund, warum der Typ im zweiten Beispiel nicht abgeleitet werden kann: int.TryParse ist eine Methodengruppe und nicht vom Typ TryParseMethod<int> .

Ich schlage vor, Sie verwenden Ansatz drei und verkürzen den Namen dieser Erweiterungsklasse. Ich glaube nicht, dass es einen besseren Weg dafür gibt.

    
Daniel Hilgarth 31.05.2011 13:06
quelle
1

Beachten Sie, dass Ihr Code funktioniert, wenn Sie zuerst Folgendes deklarieren:

%Vor%

und dann tryParser , wo du int.TryParse benutzt hast.

Das Problem ist, dass der Compiler nicht weiß, welche Überladung von int.Parse Sie sprechen. Es kann also nicht vollständig darauf schließen: Sprichst du von TryParse(String, Int32) oder TryParse(String, NumberStyles, IFormatProvider, Int32) ? Der Compiler kann nicht raten und entscheidet nicht willkürlich für Sie (zum Glück!).

Aber Ihr Delegattyp macht deutlich, an welcher Überladung Sie interessiert sind. Deshalb ist die Zuweisung von tryParser kein Problem. Sie sprechen nicht mehr von einer "Methodengruppe", sondern von einer gut identifizierten Methodensignatur innerhalb dieser Gruppe von Methoden namens int.TryParse .

    
Ssithra 31.05.2011 13:37
quelle

Tags und Links