Es wird keine vollständige Analogie zwischen C# switch
und SwitchExpression
. In der anderen Richtung, die Ansicht, dass man haben kann:
var value = Expression.Parameter(typeof(int));
var meth = Expression.Lambda<Func<int, string>>(
Expression.Switch(
value,
Expression.Call(value, typeof(object).GetMethod("ToString")),
Expression.SwitchCase(Expression.Constant("Zero"), Expression.Constant(0, typeof(int))),
Expression.SwitchCase(Expression.Constant("One"), Expression.Constant(1, typeof(int)))),
value
).Compile();
Console.WriteLine(meth(0)); // Zero
Console.WriteLine(meth(1)); // One
Console.WriteLine(meth(2)); // 2
Hier ist die SwitchExpression
gibt einen Wert, der etwas switch
nicht tun kann.
Also, nur in der Lage, etwas mit SwitchExpression
zu tun, bedeutet nicht, Sie es mit einem switch
tun können, so auch gibt es keinen Grund anzunehmen, dass mit einem switch
etwas in der Lage zu tun, bedeutet, dass Sie es mit einem SwitchExpression
tun können .
Das sagte, ich sehe keinen guten Grund, warum SwitchExpression
wurde auf diese Weise festgelegt, außer vielleicht, dass es den Fall vereinfacht, wo ein Ausdruck hat keine Fälle und keine Standard-Körper. Das heißt, ich denke, dass dies wahrscheinlich nur eine Frage des Ausdrucks war, der im Allgemeinen dazu gedacht ist, mehrere Fälle zu haben, und das war es, für dessen Unterstützung er kodifiziert wurde.
Ich habe submitted a pull-request to .NET Core, die einem solchen Fall lose Ausdrücke erlauben würde, durch eine SwitchExpression
produzieren, wo der Standardwert für die Art der switchValue
den gleichen Körper als Standard-Körper hat. Dieser Ansatz bedeutet, dass alles, was durch eine SwitchExpression
überrascht werden würde, sollte keine Fälle noch bewältigen sollte, um Rückwärtskompatibilitätsprobleme zu vermeiden. Der Fall, dass es keinen Standardwert gibt, wird durch Erstellen eines Noop-Ausdrucks behandelt, der nichts tut. Der einzige Fall, der jetzt noch ArgumentException
lautet, ist und kein Standardwert und, auf den der Typ explizit festgelegt ist etwas anderes als void
, dieser Fall ist unter den Tippregeln ungültig, die offensichtlich noch behalten werden müssen.
[Update: Dieser Ansatz wurde abgelehnt, aber a later pull-request wurde angenommen, so fall weniger SwitchExpression
s werden nun von .NET-Core erlaubt, obwohl, ob und wann die von anderen Versionen von .NET ist eine andere Sache angenommen wird].
In der Zwischenzeit, oder wenn Sie eine andere Version von verwenden.NET, sind Sie am besten-off eine Hilfsmethode verwenden wie:
public static Expression SwitchOrDefault(Type type, Expression switchValue, Expression defaultBody, MethodInfo comparison, IEnumerable<SwitchCase> cases)
{
if (cases != null)
{
// It's possible that cases is a type that can only be enumerated once.
// so we check for the most obvious condition where that isn't true
// and otherwise create a ReadOnlyCollection. ReadOnlyCollection is
// chosen because it's the most efficient within Switch itself.
if (!(cases is ICollection<SwitchCase>))
cases = new ReadOnlyCollection<SwitchCase>(cases);
if (cases.Any())
return Switch(type, switchValue, defaultBody, comparison, cases);
}
return Expression.Block(
switchValue, // include in case of side-effects.
defaultBody != null ? defaultBody : Expression.Empty() // replace null with a noop expression.
);
}
Überlastungen wie:
public static Expression SwitchOrDefault(Expression switchValue, Expression defaultBody, params SwitchCase[] cases)
{
return SwitchOrDefault(switchValue, defaultBody, null, (IEnumerable<SwitchCase>)cases);
}
und so weiter kann dann hinzugefügt werden.
Dies führt zu einem Trimmer Expression
insgesamt als meine Pull-Anfrage, weil es die switch
ganz im Fall keine Fälle ausschließt und nur die Standard-Körper zurückgibt. Wenn Sie wirklich benötigen, um eine SwitchExpression
haben, dann könnten Sie eine ähnliche Hilfsmethode erstellen, die der gleichen Logik wie diese Pull-Anforderung bei der Erstellung einer neuen SwitchCase
folgt und dann verwenden.
Was ist das Ziel einer solchen Konstruktion? 'switch' mit' default' und kein 'case' würde einfach' default' ausführen –
Für mich sieht der Switch ohne Gehäuse ziemlich bedeutungslos aus, also denke ich, dass diese Ausnahme vernünftig ist. –
Ja, die C# -Spezifikation besagt, dass ein Switch-Block aus null oder mehr Switch-Sektionen besteht; aber das bedeutet nicht, dass ein Schalterausdruck mit der C# Spezifikation übereinstimmen muss. Da Sie den Ausdruck zur Laufzeit erstellen, könnten Sie zur Umgehung einfach eine "Expression.SwitchCase" mit einem Wert hinzufügen, der! = Switch value ist; oder fügen Sie den Hauptteil des Standardfalls als einen Switch Case mit Wert = switch-Wert hinzu. – sloth