如何在使用表达式>时设置参数
本文关键字:设置 参数 Func 表达式 | 更新日期: 2023-09-27 17:56:08
我编写了以下代码来处理从数据库到数据类型的映射参数(相信我,我希望我可以使用 std. ORM,但由于多种原因,这不可行)
public void LoadDatabaseValue<T>(DataTable partData, string identifier, string mappingName, Expression<Func<T>> mappingProperty)
{
var partAttributeValue = mappingProperty.Name;
var memberExpression = (MemberExpression)mappingProperty.Body;
var prop = (PropertyInfo)memberExpression.Member;
try
{
var selectedRow = partData.Select($"partattributename = '{mappingName}'");
var selectedValue = selectedRow[0]["PartAttributeValue"];
var typedOutput = (T)Convert.ChangeType(selectedValue, typeof(T));
prop.SetValue(memberExpression.Expression, typedOutput, null);
}
catch (Exception exception)
{
_databaseImportError = true;
// code to log this error
}
当我尝试运行它时,出现以下异常
{System.Reflection.TargetException: Object does not match target type.
at System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target)
at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, Object[] index) }
当我调试它时,我的 typedOutput 与我的属性类型对齐,所以我不确定为什么它会引发此异常。
例如,我正在调用它
LoadDatabaseValue(partData, identifier, "Offset", () => Offset);
如果要保留当前的方法设计,则需要一种方法来以某种方式评估memberExpression.Expression
以便能够调用SetValue
方法。
所以换行
prop.SetValue(memberExpression.Expression, typedOutput, null);
自
prop.SetValue(Evaluate(memberExpression.Expression), typedOutput, null);
,然后使用以下实现之一:
(A) 如果您仅使用属性访问器,这将足够:
static object Evaluate(Expression e)
{
if (e == null) return null;
var me = e as MemberExpression;
if (me != null)
return ((PropertyInfo)me.Member).GetValue(Evaluate(me.Expression), null);
return ((ConstantExpression)e).Value;
}
(B)这个更普遍,但更慢:
static object Evaluate(Expression e)
{
if (e == null) return null;
return Expression.Lambda(e).Compile().DynamicInvoke();
}
SetValue
的第一个参数必须是包含要设置其值的属性的对象。
var obj = new TEntity();
prop.SetValue(obj, typedOutput); // From .NET 4.5 there is an overload with just 2 parameters
现在obj.Offset
应该具有所需的值。
因此,涉及两种类型:包含属性的对象类型和属性本身的类型(例如 int
、string
等)。
因此,您的表达式应如下所示:
Expression<Func<TEntity, object>> mappingProperty
其中TEntity
是对象的类型,object
是该对象的属性的未知类型。除非您事先知道房产的类型,否则您将拥有
Expression<Func<TEntity, TProperty>> mappingProperty
你可以这样称呼它:
LoadDatabaseValue(partData, identifier, "Offset", x => x.Offset);
您必须像这样更改类型(除非selectedValue
已经属于正确的类型):
object typedOutput = Convert.ChangeType(selectedValue, prop.PropertyType);