构建字符串转枚举的表达式树时遇ArgumentException异常,同时需实现异常信息中获取输入参数值
构建字符串转枚举的表达式树时遇ArgumentException异常,同时需实现异常信息中获取输入参数值
嗨,我来帮你梳理并解决这个问题~
先说说你遇到的异常原因
你碰到的System.ArgumentException核心问题在于:Expression.IfThenElse是一个无返回值(void类型)的表达式,它只负责执行两个分支的逻辑,但不会返回任何结果;而你要构建的Func<TString, TEnum> Lambda要求body必须返回TEnum类型的值,类型不匹配自然就报错了。
再解决两个核心需求:修复异常 + 异常消息包含输入值
我们需要做两个关键调整:
- 用**有返回值的分支表达式
Expression.Condition**替代Expression.IfThenElse,让Lambda的body能返回正确类型的结果; - 动态构建异常消息,通过表达式调用字符串格式化方法,把输入参数的值嵌入到异常描述里。
修正后的完整代码
public static Func<TString, TEnum> BuildStringToEnumConvertor<TString, TEnum>() { var enumType = typeof(TEnum); var enumTypeExp = Expression.Constant(enumType); var dbValueExp = Expression.Parameter(typeof(TString), "dbValue"); // 构建Enum.IsDefined的调用表达式 var isDefinedMethod = typeof(Enum).GetMethod("IsDefined", new[] { typeof(Type), typeof(object) }); var testExp = Expression.Call(null, isDefinedMethod, enumTypeExp, Expression.Convert(dbValueExp, typeof(object))); // 构建Enum.Parse的调用及转换逻辑 var parseMethod = typeof(Enum).GetMethod("Parse", new[] { typeof(Type), typeof(string) }); var strExp = Expression.Convert(Expression.Convert(dbValueExp, typeof(object)), typeof(string)); var parsedExp = Expression.Call(null, parseMethod, enumTypeExp, strExp); var objExp = Expression.Convert(parsedExp, enumType); // 动态构建包含输入参数的异常消息 var errorTemplate = Expression.Constant($"Could not convert '{{0}}' to type '{enumType.Name}'."); var formattedErrorMsg = Expression.Call( typeof(string), "Format", Type.EmptyTypes, errorTemplate, dbValueExp ); // 创建异常表达式,并指定返回类型为TEnum(让分支类型匹配) var exceptionCtor = typeof(Exception).GetConstructor(new[] { typeof(string) }); var throwExp = Expression.Throw( Expression.New(exceptionCtor, formattedErrorMsg), enumType ); // 用Condition替代IfThenElse,确保有返回值 var bodyExp = Expression.Condition(testExp, objExp, throwExp); // 构建并编译Lambda return Expression.Lambda<Func<TString, TEnum>>(bodyExp, dbValueExp).Compile(); } internal enum TestEnum { Age = 1, Name, Address, CellPhone, Max = 500 }
关键调整点说明
- 替换IfThenElse为Condition:
Expression.Condition会根据测试表达式的结果,返回两个分支中符合指定类型的结果,完美适配Lambda对返回值的要求; - 动态异常消息:通过
Expression.Call调用string.Format,把输入参数dbValueExp作为格式化参数传入,这样异常消息就能动态包含实际的输入值; - 指定Throw的返回类型:
Expression.Throw默认返回void,我们显式指定返回类型为TEnum,保证Condition的两个分支类型完全一致(都是TEnum),避免类型不匹配的问题。
测试效果
当你调用var func = BuildStringToEnumConvertor<string, TestEnum>();,然后执行func("InvalidValue");时,会抛出异常,异常消息会显示:Could not convert 'InvalidValue' to type 'TestEnum'.,完美包含了输入的参数值。
备注:内容来源于stack exchange,提问作者long
相关产品推荐
相关产品推荐

