簡體   English   中英

在編譯時設置屬性而不知道目標類型

[英]Setting property without knowing target type at compile time

我想在編譯時不知道對象類型的情況下在對象上設置屬性值; 我希望它快速(即每次都不使用反射); 我知道屬性名稱和類型。

最快的方式(afaik)是使用代表; 所以這就是我到目前為止所擁有的:

class User // this is an example.. Assume I don't know which type this is.
 {
    public string Name {get;set;}   
 }

public static Action<object, object> CreatePropertySetter(Type targetType, string propertyName)
{
    ParameterExpression targetObjParamExpr = Expression.Parameter(targetType);
    ParameterExpression valueParamExpr = Expression.Parameter(targetType.GetProperty(propertyName).PropertyType);

    MemberExpression propertyExpr = Expression.Property(targetObjParamExpr, propertyName);

    BinaryExpression assignExpr = Expression.Assign(targetObjParamExpr, valueParamExpr);

    Action<object, object> result = Expression.Lambda<Action<object, object>>(assignExpr, targetObjParamExpr, valueParamExpr).Compile();
    return result;
}

然后我打電話:

User user = new User();
var userNameSetter = CreatePropertySetter(user.GetType(), "Name");
userNameSetter(user, "Bob");

但是,它不喜歡我傳遞User類型對象而不是Object的事實,並且失敗並且“ UserExpression類型'User'不能用於'System.Object'類型的委托參數

我是表達樹木的新手,所以有點迷失在這里。 為什么不能將User轉換為對象? 我需要某個演員嗎?

“行動”看起來也不好看; 只返回一個帶參數的委托(User user,string propertyValue)會更好。 再次,不知道如何實現這一目標。 實際上,我已經嘗試過Delegate.CreateDelegate,但它使用.Invoke()方法調用,這很慢(這是唯一的方法嗎?); 與Expression.Lambda(非泛型)相同。

有什么想法嗎 ?

另外,表達樹上有一個好的(比msdn好)文檔嗎? msdn版本確實缺乏細節。

如果你想使用Expression,那么: Convert ......

static void Main()
{
    var setter = CreatePropertySetter(typeof (User), "Name");
    var obj = new User();
    setter(obj, "Fred");
}
public static Action<object, object> CreatePropertySetter(Type targetType, string propertyName)
{
    var target = Expression.Parameter(typeof (object), "obj");
    var value = Expression.Parameter(typeof (object), "value");
    var property = targetType.GetProperty(propertyName);
    var body = Expression.Assign(
        Expression.Property(Expression.Convert(target, property.DeclaringType), property),
        Expression.Convert(value, property.PropertyType));

    var lambda = Expression.Lambda<Action<object, object>>(body, target, value);
    return lambda.Compile();
}

然而! 你可能想看看FastMember (也可以在NuGet上找到),它可以非常方便地為你提供所有這些(並使用原始的IL來進行愚蠢的瘋狂)。

如果要使用類型化的委托,則需要事先知道類型。 如果您知道類型,可以添加一些通用:

static void Main()
{
    var setter = CreatePropertySetter<User,string>("Name");
    var obj = new User();
    setter(obj, "Fred");
}
public static Action<TType, TValue> CreatePropertySetter<TType, TValue>(string propertyName)
{
    var target = Expression.Parameter(typeof (TType), "obj");
    var value = Expression.Parameter(typeof (TValue), "value");
    var property = typeof(TType).GetProperty(propertyName);
    var body = Expression.Assign(
        Expression.Property(target, property),
        value);

    var lambda = Expression.Lambda<Action<TType, TValue>>(body, target, value);
    return lambda.Compile();
}

暫無
暫無

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

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