我如何创建一个表达式,它要么抛出异常,要么根据条件 returns 一个值?

How can I create an expression that either throws an exception or returns a value based on a condition?

我正在努力构建一个表达式,如果条件为真则抛出异常,如果条件为假则应该 return 一个值,但我总是得到 ArgumentException:

var expr =
    Expression.Condition(
        Expression.Equal(Expression.Constant(0), Expression.Constant(0)),
        Expression.Throw(Expression.Constant(new DivideByZeroException())),
        Expression.Constant(1));
var lambda = Expression.Lambda<Func<int>>(expr);
var result = lambda.Compile()();

如果我将 Expression.Empty() 作为 Condition 的第三个参数,它就会运行,但如果条件为假,我得不到想要的结果。

这样就可以了。

var expr =
    Expression.Block(
        Expression.IfThen(
            Expression.Equal(Expression.Constant(1), Expression.Constant(1)),
            Expression.Throw(
                Expression.New(typeof(DivideByZeroException))
            )
        ),
        Expression.Constant(1)
    );
var lambda = Expression.Lambda<Func<int>>(expr);
var result = lambda.Compile()();

Conditional 更类似于三元运算符。所以你写的更等同于 C#:

return (0 == 0) ? throw new DivideByZeroException() : 1;

我将您的常量异常更改为动态创建的异常,我假设这是首选。

条件表达式必须return来自每个分支的相同类型。你正在尝试的相当于

var x = 0==0 ? throw new DivideByZeroException() : 1;

这是无效的。你可以 导致 DivideByZeroException:

var expr =
Expression.Condition(
    Expression.Equal(Expression.Constant(0), Expression.Constant(0)),
    Expression.Divide(Expression.Constant(1), Expression.Constant(0)),
    Expression.Constant(1));

只需创建一个为您抛出异常并具有您想要的任何类型的方法:

public static T ThrowHelper<T>(Exception e)
{
    throw e;
}

然后创建调用该方法的表达式。这使得抛出表达式的行为成为表达式,而不是语句,并允许该表达式具有您想要的任何类型:

var throwMethod = typeof(TheClassThrowIsIn)
    .GetMethod("ThrowHelper", BindingFlags.Static)
    .MakeGenericMethod(typeof(int));
var expr =
    Expression.Condition(
        Expression.Equal(Expression.Constant(0), Expression.Constant(0)),
        Expression.Call(throwMethod, Expression.Constant(new DivideByZeroException())),
        Expression.Constant(1));

使用带有两个参数的Expression.Throw,第二个参数包含结果表达式值的类型。

https://docs.microsoft.com/en-us/dotnet/api/system.linq.expressions.expression.throw?view=netframework-4.7.2#System_Linq_Expressions_Expression_Throw_System_Linq_Expressions_Expression_System_Type_