我正在尝试将方法转换为表达式树进行测试,但出现错误
抛出异常: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
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);