簡體   English   中英

使用Expression時如何設置參數 <Func<T> &gt;

[英]How to set a parameter while using Expression<Func<T>>

我已經編寫了以下代碼來處理從數據庫到數據類型的映射參數(相信我,我希望我可以使用標准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應該具有所需的值。

因此涉及兩種類型:包含屬性的對象的類型和屬性本身的類型(例如intstring等)。

因此,您的表達式應如下所示:

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);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM