Вопрос по c#, c#-4.0 – Установка свойства без знания типа цели во время компиляции

3

Я хочу установить значение свойства для объекта, не зная тип объекта во время компиляции; Я хочу, чтобы он был быстрым (т.е. не использовал Reflection каждый раз); Я знаю название и тип недвижимости.

Самый быстрый способ (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");

Однако ему не нравится тот факт, что я передаю объект типа пользователя вместо объекта, и происходит сбой с & quot;ParameterExpression of type 'User' cannot be used for delegate parameter of type 'System.Object& Quot ;.

Я новичок в деревьях выражений, поэтому немного потерян здесь. Почему он не может привести пользователя к объекту? Мне нужен актерский состав где-нибудь?

& Quot; Действие & quot; тоже не очень хорошо выглядит; было бы лучше просто вернуть делегат, принимающий аргументы (пользователь, строка, propertyValue). Опять же, не уверен, как это сделать. На самом деле, я пробовал это с Delegate.CreateDelegate, но он вызывается с использованием метода .Invoke (), который медленный (это единственный способ?); то же самое с Expression.Lambda (не универсальный).

Какие-нибудь мысли ?

Кроме того, есть ли хорошая (лучше, чем msdn) документация по деревьям выражений? Версия MSDN действительно не хватает деталей.

Это может быть то, что вы ищетеConvert.ChangeType Method (Object, Type) asawyer
Ред. Хотя это было краткое изложение всего вопроса, и было достаточно деталей, чтобы дать ответ, IMO. Evgeni
TL;DR Не делай этого. Напишите четкие краткие вопросы с соответствующей информацией и деталями. asawyer
ЯвляетсяUser тип значения или ссылочный тип? Thomas Levesque
Это немного в стороне, но вы чувствуете, что вы программист на C ++, который привык использовать шаблоны, но теперь не может на C #. Это было бы тривиально в C ++. Kevin Anderson

Ваш Ответ

1   ответ
9

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), котороеall это для вас очень удобно (и использует сырой IL для глупого сумасшествия).

Если вы хотите использовать типизированный делегат, вам нужно знать типы заранее. если тыknow типы, вы можете добавить некоторые общие:

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();
}
Error: User Rate Limit Exceeded Evgeni
Error: User Rate Limit Exceeded

Похожие вопросы