我试图用System.Linq.Expressions创建一个开关表达式:
var value = Expression.Parameter(typeof(int));
var defaultBody = Expression.Constant(0);
var cases1 = new[] { Expression.SwitchCase(Expression.Constant(1), Expression.Constant(1)), };
var cases2 = new SwitchCase[0];
var switch1 = Expression.Switch(value, defaultBody, cases1);
var switch2 = Expression.Switch(value, defaultBody, cases2);
但在最后一行中,我得到了ArgumentException:
需要非空收集。参数名称:案例
发生此异常的原因是什么?这可能是Expression.Switch(...)中的错误吗?
在C#中,仅具有“默认”部分的开关是正确的:
switch(expr) {
default:
return 0;
}//switch
UPD:我已向GitHub上的CoreFX存储库提交了一个问题
C#switch
和之间没有完全的类比SwitchExpression
。另一方面,请考虑您可以:
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
在这里,SwitchExpression
返回值是switch
做不到的。
因此,就像可以做某事SwitchExpression
并不意味着您可以用做某事switch
,因此也没有理由假设可以用某事做某事而switch
您可以对做某事SwitchExpression
。
就是说,我认为没有理由SwitchExpression
设置这种方式,除了它可以简化表达式没有大小写且没有默认主体的情况。就是说,我认为这可能只是表达通常要包含多个案例的问题,而这正是它被编码为支持的内容。
我已经向.NET Core提交了一个pull-request请求,该请求将通过生成一个SwitchExpression
where类型的默认值switchValue
与默认主体相同的主体,从而允许这种不分大小写的表达式。这种方法意味着SwitchExpression
没有案例的情况下,任何令人惊讶的事情都应该解决,避免了向后兼容的问题。通过创建不执行任何操作的noop表达式来处理没有默认值的情况,因此,现在仍然抛出一个唯一的情况ArgumentException
是,如果没有大小写且没有默认值,并且类型明确设置为void
,在明显必须保留的打字规则下,这种情况无效。
[更新:该方法已被拒绝,但后来的请求请求被接受,因此SwitchExpression
.NET Core现在允许使用不区分大小写的,尽管其他版本的.NET是否以及何时采用它是另一回事]。
同时,或者如果您使用其他版本的.NET,则最好使用以下帮助方法:
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.
);
}
重载如下:
public static Expression SwitchOrDefault(Expression switchValue, Expression defaultBody, params SwitchCase[] cases)
{
return SwitchOrDefault(switchValue, defaultBody, null, (IEnumerable<SwitchCase>)cases);
}
然后可以添加等等。
这Expression
比我的pull-request总体上要更整齐,因为它switch
在没有大小写的情况下完全切掉了,只返回默认主体。如果确实需要a,SwitchExpression
则可以创建类似的帮助程序方法,该方法遵循与pull-request在创建新的SwitchCase
然后使用它时所做的逻辑相同的逻辑。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句