Kann ein C# - lambda-Ausdruck immer void zurück?
Habe ich die folgende Methode, und ich möchte wissen, ob es irgendetwas gibt, was gehen kann in place Standard - (void) unten denn es gibt eine compiler-Fehlermeldung, die sagt, dass die ungültig ist nicht gültig hier:
private void applyDefaultsIfNecessary(ApplicationConfiguration configuration)
{
var defaults = new Dictionary<Predicate<ApplicationConfiguration>, Action<ApplicationConfiguration>>()
{
//{ rule, action } - if rule is true, execute action
{ (c) => c.ConnectionString == null , (c) => c.ConnectionString = "foo" },
{ (c) => c.OutputExcelFilePath == null, (c) => c.ConnectionString = "bar" },
{ (c) => c.OutputDirectory == null, (c) => c.OutputDirectory = "baz" }
};
//Nothing to select, but we want to loop throough the dict and invoke action, if rule is true.
//It is a pity there is no extension method called DoForEach on collections.
defaults.Select((item) => item.Key.Invoke(configuration) ? item.Value.Invoke(configuration) : default(void) );
}
Merke ich, dass ich kann verwenden Sie die if-else-Anweisung anstelle der ternäre operator (oder ich könnte ein dummy-Methode void zurück). Auch die Select-Erweiterungsmethode nicht wie Lambda-Ausdrücke, die "void" zurückgeben. Es scheint zu sagen, dass der Typ nicht abgeleitet werden, aber natürlich, wenn ich den Typ angeben, wie diese, entweder:
defaults.Select<ApplicationConfiguration, void>((item) => { if (item.Key.Invoke(configuration)) item.Value.Invoke(configuration); } );
War ich neugierig von einem design-Sprache Standpunkt, warum wir uns nicht Ausdrücken können "void" zurückgeben oder den Datentyp für Variablen, ist nichtig.
- "Es ist schade, dass es keine Erweiterung Methode namens DoForEach auf collections" es dauert etwa 3 Zeilen code hinzu, um eine extenssion IEnumerable, genau das zu tun
- Sind Sie sicher, dass Sie don ' T mean return NULL anstelle von void?
- Rusanu: Lesen - es gibt einen guten Grund, das war noch nicht Hinzugefügt. Meiner Meinung nach, ist es eine Schande, Sie haben es auf List<T>: blogs.msdn.com/ericlippert/archive/2009/05/18/...
- Ersetzen von Standard - (void) mit null nicht helfen, entweder. Der compiler sagt es ist keine implict Konvertierung zwischen null und nichtig
- Wählen Sie müssen etwas zurückgeben. Sie können nicht nur verwenden Sie eine Aktion wählen - Sie haben immer zu machen, wählen Sie wieder einige Typ T, und leere ist nichts", so funktioniert es nicht.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Verweise ich Sie auf Abschnitt 7.1 der Spezifikation, die besagt:
[Hervorhebung Hinzugefügt].
Ist zu sagen, dass das einzige mal, können Sie einen Ausdruck verwenden, der ein "void" zurückgegeben method invocation ist, wenn der Ausdruck der macht, bis eine komplette Aussage. Wie diese:
void
Ausdruck der rechten Seite der=>
lambda-Pfeil. Der gesamte Ausdruck inklusive der Pfeil nicht haben eine Art an sich. Und in dem Fall, wo die=>
konvertiert werden muss, um einen Ausdruck-Baum, nicht writtens als ein block mit einer einzigen Anweisung. Zum BeispielExpression<Action> tree = () => Console.WriteLine("Hello");
legal ist, und erscheint, enthält ein sub-Ausdruck vom Typvoid
.Expression<Action> tree2 = () => { Console.WriteLine("Hello"); };
wird nicht kompilieren, da die Anweisung Körper{ ... }
ist nicht erlaubt, für expression-Bäume.Dies ist in der Tat eine Verletzung der funktionalen Programmierung zu Regeln. Dies hat den gleichen Fehler Eric Lippert beschrieben, über die Liste.ForEach: Du bist philosphically versuchen, um Nebenwirkungen zu verursachen, die auf Ihre Sammlung.
Durchlaufen werden.Wählen Sie vorgesehen ist, um wieder eine neue Sammlung - das filtern des Eingangssignals. Es ist nicht beabsichtigt, um code auszuführen.
Dass gesagt wird, Sie kann umgehen, indem wir tun:
Es ist nur nicht so klar, wie zu tun:
Sprache Standpunkt
void
bedeutet "nicht vorhanden", das wirft die Frage auf: welchen Wert könnte es sein, deklarieren Sie eine variable, die nicht existiert?Das problem hier ist nicht eine Sprache, die Beschränkung, sondern die Tatsache, dass Sie ein Konstrukt (der ternäre operator), dass verlangt zwei rvalues-wo du nur eine haben.
Wenn ich kann, ehrlich gesagt, ich würde sagen, Sie sind die Vermeidung von if/else zu Gunsten von sinnlos Kürze. Alle tricks, die Sie kommen mit zu ersetzen
default(void)
werden nur dazu dienen, verwirren andere Entwickler, oder Sie, in der Zukunft, lange nachdem Sie aufgehört habe Mühe mit dieser Art der Sache.Erstens, sollten Sie wirklich vermeiden, dass Nebenwirkungen, die in den standard-linq-abfrageoperatoren, und zweitens ist diese nicht wirklich funktionieren, da Sie nicht aufzählen die Select-Abfrage, anywhere. Wenn Sie möchten, verwenden Sie linq-Sie könnten dies tun:
Bezüglich Ihrer Frage, ich bin mir ziemlich sicher, dass es keine mögliche Werte nichtig, und Sie können nicht zurückkehren es ausdrücklich. In funktionalen Sprachen wie F#, ungültig ist ersetzt durch "Einheit", d.h. ein Typ mit nur einem möglichen Wert - wenn man wollte, könnte man erstellen Sie Ihre eigene Einheit geben und zurückgeben. In diesem Fall könnten Sie so etwas tun:
Aber ich kann wirklich nicht empfehlen dies zu tun.
Standard funktioniert nicht mit leere; es funktioniert aber mit einem Typ. Der Action-Klasse erzeugt kein Ergebnis, aber die Func - <> Objekt hat immer ein Ergebnis zurückgeben. Was auch immer Element.Wert.Invoke() gibt einfach nur wieder die Standardeinstellung, dass, wie in:
Standard(Objekt)
ist oder ob es eine bestimmte Art:
Standard(SomeType)
So.