Frage

Ich habe den folgenden Code:

Func<string, bool> comparer = delegate(string value) {
    return value != "0";
};

Folgendes wird jedoch nicht kompiliert:

var comparer = delegate(string value) {
    return value != "0";
};

Warum kann der Compiler nicht herausfinden, dass es sich um eine handelt Func<string, bool>?Es benötigt einen String-Parameter und gibt einen booleschen Wert zurück.Stattdessen erhalte ich die Fehlermeldung:

Eine anonyme Methode kann einer lokalen Variablen implizit nicht zuweisen.

Ich habe eine Vermutung, und zwar wenn die var-Version kompiliert wurde, es würde an Konsistenz mangeln, wenn ich Folgendes hätte:

var comparer = delegate(string arg1, string arg2, string arg3, string arg4, string arg5) {
    return false;
};

Das Obige würde keinen Sinn ergeben, da Func<> nur bis zu 4 Argumente zulässt (in .NET 3.5, was ich verwende).Vielleicht könnte jemand das Problem klären.Danke.

War es hilfreich?

Lösung

Andere haben bereits darauf hingewiesen, dass es unendlich viele mögliche Delegatentypen gibt könnte gemeint haben;Was ist das Besondere daran? Func dass es stattdessen die Standardeinstellung verdient Predicate oder Action oder irgendeine andere Möglichkeit?Und warum ist es bei Lambdas offensichtlich, dass die Absicht darin besteht, die Delegatenform und nicht die Ausdrucksbaumform zu wählen?

Aber das könnten wir sagen Func etwas Besonderes ist und dass der abgeleitete Typ eines Lambda oder einer anonymen Methode Func von etwas ist.Wir hätten immer noch alle möglichen Probleme.Welche Typen möchten Sie für die folgenden Fälle abgeleitet werden?

var x1 = (ref int y)=>123;

Es gibt kein Func<T> Typ, der einen Ref irgendetwas annimmt.

var x2 = y=>123;

Wir kennen den Typ des formalen Parameters nicht, wohl aber die Rückgabe.(Oder tun wir?Ist die Rückgabe int?lang?kurz?Byte?)

var x3 = (int y)=>null;

Wir kennen den Rückgabetyp nicht, aber er kann nicht ungültig sein.Der Rückgabetyp kann ein beliebiger Referenztyp oder ein beliebiger Nullable-Werttyp sein.

var x4 = (int y)=>{ throw new Exception(); }

Auch hier kennen wir den Rückgabetyp nicht, und dieses Mal kennen wir ihn dürfen nichtig sein.

var x5 = (int y)=> q += y;

Soll das ein ungültiges Anweisungs-Lambda sein oder etwas, das den Wert zurückgibt, der q zugewiesen wurde?Beides ist legal;was sollen wir wählen?

Nun könnte man sagen: Unterstützen Sie einfach keine dieser Funktionen.Unterstützen Sie einfach „normale“ Fälle, in denen die Typen ermittelt werden können.Das hilft nicht.Wie erleichtert mir das das Leben?Wenn die Funktion manchmal funktioniert und manchmal fehlschlägt, muss ich trotzdem den Code schreiben erkennen all diese Fehlersituationen und gib a sinnvolle Fehlermeldung für jede.Wir müssen noch all dieses Verhalten spezifizieren, es dokumentieren, Tests dafür schreiben und so weiter.Das ist ein sehr teure Funktion Das erspart dem Benutzer vielleicht ein halbes Dutzend Tastenanschläge.Wir haben bessere Möglichkeiten, der Sprache einen Mehrwert zu verleihen, als viel Zeit damit zu verbringen, Testfälle für eine Funktion zu schreiben, die in der Hälfte der Zeit nicht funktioniert und in den Fällen, in denen sie funktioniert, kaum einen Nutzen bringt.

Die Situation, in der es tatsächlich nützlich ist, ist:

var xAnon = (int y)=>new { Y = y };

weil es für dieses Ding keinen „aussprechlichen“ Typ gibt.Aber wir haben dieses Problem ständig und verwenden einfach die Methodentypinferenz, um den Typ abzuleiten:

Func<A, R> WorkItOut<A, R>(Func<A, R> f) { return f; }
...
var xAnon = WorkItOut((int y)=>new { Y = y });

und jetzt ermittelt die Methodentyp-Inferenz, um welchen Funktionstyp es sich handelt.

Andere Tipps

Nur Eric Lippert weiß es mit Sicherheit, aber ich denke, das liegt daran, dass die Signatur des Delegatentyps den Typ nicht eindeutig bestimmt.

Betrachten Sie Ihr Beispiel:

var comparer = delegate(string value) { return value != "0"; };

Hier sind zwei mögliche Schlussfolgerungen für das, was var sollte sein:

Predicate<string> comparer  = delegate(string value) { return value != "0"; };  // okay
Func<string, bool> comparer = delegate(string value) { return value != "0"; };  // also okay

Auf welches sollte der Compiler schließen?Es gibt keinen guten Grund, sich für das eine oder das andere zu entscheiden.Und obwohl a Predicate<T> ist funktional äquivalent zu a Func<T, bool>, es handelt sich immer noch um unterschiedliche Typen auf der Ebene des .NET-Typsystems.Der Compiler kann den Delegatentyp daher nicht eindeutig auflösen und muss die Typinferenz scheitern lassen.

Eric Lippert hat ein altes post darüber, wo er sagt

und tatsächlich die C # 2.0-Spezifikation ruft das auf.Methodengruppe Ausdrücke und anonyme Methode Ausdrücke sind typlose Ausdrücke In C # 2.0 und Lambda-Ausdrücke kommen an sie in c # 3.0.Daher ist es illegal für sie, auf "nackt" aufzusehen die rechte Seite eines impliziten Erklärung.

Unterschiedliche Delegierte werden als unterschiedliche Typen betrachtet.z.B., Action ist anders als MethodInvoker, und eine Instanz von Action kann keiner Variablen des Typs zugewiesen werden MethodInvoker.

Also, gegeben ein anonymer Delegierter (oder Lambda) wie () => {}, ist es ein Action oder ein MethodInvoker?Der Compiler kann es nicht sagen.

Ebenso, wenn ich einen Delegatentyp deklariere, der a annimmt string Argument und Rückgabe von a bool, woher soll der Compiler wissen, dass Sie wirklich eine wollten Func<string, bool> anstelle meines Delegatentyps?Es kann nicht auf den Delegatentyp geschlossen werden.

Die folgenden Punkte stammen aus dem MSDN in Bezug auf implizit eingegebene lokale Variablen:

    .
  1. var kann nur verwendet werden, wenn eine lokale Variable in derselben Anweisung deklariert und initialisiert wird; Die Variable kann nicht auf NULL initialisiert werden, oder in einer Methodengruppe oder einer anonymen Funktion.
  2. Das VAR-Schlüsselwort weist den Compiler an, den Typ der Variablen vom Ausdruck auf der rechten Seite der Initialisierungsanweisung abzuleiten.
  3. Es ist wichtig zu verstehen, dass das Schlüsselwort VARE nicht "Variante" bedeutet, und deuten nicht darauf hin, dass die Variable lose typisiert oder spät gebunden ist. Es bedeutet nur, dass der Compiler den am besten geeigneten Typ bestimmt und zuordnet.

    MSDN-Referenz: Implizit eingegebene lokale Variablen

    In Anbetracht der folgenden anonymen Methoden:

      .
    1. Anonyme Methoden ermöglichen es Ihnen, die Parameterliste wegzulassen.

      MSDN-Referenz: Anonyme Methoden

      Ich würde vermuten, dass, da das anonyme Verfahren tatsächlich unterschiedliche Methodensignaturen aufweist, der Compiler nicht ordnungsgemäß anschließt, was der am besten geeignete Typ zum Zuweisen ist.

Mein Beitrag beantwortet nicht die eigentliche Frage, aber er beantwortet die zugrunde liegende Frage:

„Wie vermeide ich es, irgendeine hässliche Schriftart wie … abtippen zu müssen? Func<string, string, int, CustomInputType, bool, ReturnType>?" [1]

Da ich der faule/hackige Programmierer bin, habe ich mit der Verwendung experimentiert Func<dynamic, object> - das einen einzelnen Eingabeparameter entgegennimmt und ein Objekt zurückgibt.

Für mehrere Argumente können Sie es wie folgt verwenden:

dynamic myParams = new ExpandoObject();
myParams.arg0 = "whatever";
myParams.arg1 = 3;
Func<dynamic, object> y = (dynObj) =>
{
    return dynObj.arg0.ToUpper() + (dynObj.arg1 * 45); //screw type casting, amirite?
};
Console.WriteLine(y(myParams));

Tipp:Sie können verwenden Action<dynamic> wenn Sie kein Objekt zurückgeben müssen.

Ja, ich weiß, dass es wahrscheinlich gegen Ihre Programmierprinzipien verstößt, aber das macht für mich und wahrscheinlich einige Python-Programmierer Sinn.

Ich bin ziemlicher Neuling im Delegieren...Ich wollte nur mitteilen, was ich gelernt habe.


[1] Dies setzt voraus, dass Sie keine Methode aufrufen, die eine vordefinierte Methode erfordert Func als Parameter, in diesem Fall müssen Sie diese hässliche Zeichenfolge eingeben :/

Wie geht es danach? generasacodicetagpre.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top