尝试将方法转换为表达式树时,出现错误“System.Void”不能用于返回类型“”

问题描述 投票:0回答:1

我正在尝试将方法转换为表达式树进行测试,但出现错误

抛出异常:System.Linq.Expressions.dll中的“System.ArgumentException”类型“System.Void”的表达式不能用于返回类型“TestDatabase.Models.TestEnum”

同时,我想知道如何获取输入值作为异常测试的输出。

我尝试重新创建表达式树的原始方法是:

private TEnum ConvertStringToEnum(TDbValueType dbValue)
{
    if (Enum.IsDefined(typeof(TEnum), dbValue))
    {
        return (TEnum)Enum.Parse(typeof(TEnum), (string)(object)dbValue);
    }

    throw new Exception("");
}

表达式树的构建方法是

public static Func<TString, TEnum> BuildStringToEnumConvertor<TString, TEnum>()
{
    var enumType = typeof(TEnum);
    var enumTypeExp = Expression.Constant(enumType);

    //var labeleExp = Expression.Label(enumType);

    var dbValueExp = Expression.Parameter(typeof(TString), "dbValue");
    var m = typeof(Enum).GetMethod("IsDefined", [typeof(Type), typeof(object)]);

    //test
    var testExp = Expression.Call(null, m, enumTypeExp, dbValueExp);

    //true
    var objExp = Expression.Convert(dbValueExp, typeof(object));
    var strExp = Expression.Convert(objExp, typeof(string));

    m = typeof(Enum).GetMethod("Parse", [typeof(Type), typeof(string)]);
    var retExp = Expression.Call(null, m, enumTypeExp, strExp);
    objExp = Expression.Convert(retExp, enumType);

    //var returnExp = Expression.Return(labeleExp, objExp);

    //false
    //var x = Expression.Lambda<Func<string>>(dbValueExp).CompileFast();
    //var x = Expression.Lambda<Func<string>>(dbValueExp).Compile();

    var falseExp = Expression.Throw(Expression.Constant(new Exception($"could not convert \" {{how to get the input parameter value ??}} \" to type \"{typeof(TEnum).Name}\".")));

    var xxExp = Expression.IfThenElse(testExp, objExp, falseExp);

    //var block = Expression.Block(objExp, falseExp);

    //return Expression.Lambda<Func<TString, TEnum>>(block, dbValueExp).CompileFast();
    return Expression.Lambda<Func<TString, TEnum>>(xxExp, dbValueExp).Compile(); <-- error here 

}


internal enum TestEnum
{
    Age = 1,
    Name,
    Address,
    CellPhone,
    Max = 500
}

当我致电

var func = BuildStringToEnumConvertor<string, TestEnum>();
时,我收到以下异常:

Unhandled exception. System.ArgumentException: Expression of type 'System.Void' cannot be used for return type 'Program+TestEnum'
   at System.Linq.Expressions.Expression.ValidateLambdaArgs(Type delegateType, Expression& body, ReadOnlyCollection`1 parameters, String paramName)
   at System.Linq.Expressions.Expression.Lambda[TDelegate](Expression body, String name, Boolean tailCall, IEnumerable`1 parameters)
   at Program.BuildStringToEnumConvertor[TString,TEnum]()

在此处运行演示:https://dotnetfiddle.net/IkYEpJ

c# expression-trees
1个回答
4
投票

Expression.IfThenElse
返回的类型始终为 void,要指定类型,请使用
Expression.Condition
:

Expression.Condition(testExp, objExp, falseExp, enumType);

您还需要为 throw 表达式指定类型:

Expression.Throw(Expression.Constant(new Exception("")), enumType);

获取输入参数值,可以手动构造异常对象

// string.Concat(string, string, string)
var concat = typeof(string).GetMethod("Concat", [typeof(string),
                                                 typeof(string),
                                                 typeof(string)]);

// Concat constant strings with the parameter
var msg = Expression.Call(concat,
                Expression.Constant(@"could not convert """),
                strExp,
                Expression.Constant($@""" to type ""{typeof(TEnum).Name}""."))

// Create an exception object with the error message
var ex = Expression.New(typeof(Exception).GetConstructor([typeof(string)]), msg);

// Emit throw statement
var falseExp = Expression.Throw(ex, enumType);
© www.soinside.com 2019 - 2024. All rights reserved.