Как установить значения свойств для индексаторов с помощью выражений? - PullRequest
0 голосов
/ 14 декабря 2018

В настоящее время я застрял с установкой значения в выражении индексатора, переданного в следующую функцию:

private static void SetPropertyValue<T, TValue>(this T target, Expression<Func<T, TValue>> memberLamda, TValue value)
{
    var memberSelectorExpression = memberLamda.Body as MemberExpression;
    if (memberSelectorExpression != null)
    {
        var property = memberSelectorExpression.Member as PropertyInfo;
        if (property != null)
        {
            property.SetValue(target, value, null);
            return;
        }
    }
}

У меня есть следующий класс

class Entity 
{
    public object this[string name] 
    {
        get { /* */ }
        set { /* */ }
    }
}

Когда я сейчас вызываюв предыдущей определенной функции со следующими значениями я получаю только ссылку на метод поддержки get_Item():

var entity = new Entity();
// ...
SetPropertyValue(entity, x => x[memberName], value);

Есть ли у кого-нибудь подсказка для меня, как решить эту проблему?Любая идея поможет.

Большое спасибо всем вам ...

1 Ответ

0 голосов
/ 14 декабря 2018

Я думаю, что вижу то, что вы пытаетесь - одно расширение SetPropertyValue, которое работает для обычных и индексированных свойств.В этом случае вам нужно определить тип ссылки в переданном в Expression, чтобы определить, как вызвать SetValue:

public static void SetPropertyValue<T, TValue>(this T target, Expression<Func<T,TValue>> memberFn, TValue value) {
    var b = memberFn.Body;
    if (b is MethodCallExpression bc && bc.Method.IsSpecialName && bc.Method.Name.StartsWith("get_")) {
        var PI = typeof(T).GetProperty(bc.Method.Name.Substring(4));
        PI.SetValue(target, value, bc.Arguments.Select(a => a.Evaluate<object>()).ToArray());
    }
    else if (b is MemberExpression bm) {
        var pi = bm.Member;
        pi.SetValue(target, value);
    }
}

. Вы можете определить индексированное имя свойства несколькими различными способами, ярешил предположить, что за специальным именем, начинающимся с get_, последует индексированное имя свойства (текущие компиляторы C # используют Item) и используйте его для поиска свойства.Если компилятор изменил шаблон имени (например, Item_get), я не вижу никакой связи между MethodInfo метода get и свойством, которое он представляет, поэтому вам придется переписать этот код, нов любом случае это всегда опасность отражения.Возможно, поиск свойства, имя которого содержится в имени метода get, будет несколько более надежным, если будет медленнее.

Вот версия, которая делает это:

public static void SetPropertyValue<T, TValue>(this T target, Expression<Func<T,TValue>> memberFn, TValue value) {
    var b = memberFn.Body;
    if (b is MethodCallExpression bc && bc.Method.IsSpecialName) {
        var PI = typeof(T).GetProperties().First(pi => bc.Method.Name.Contains(pi.Name));
        PI.SetValue(target, value, bc.Arguments.Select(a => a.Evaluate<object>()).ToArray());
    }
    else if (b is MemberExpression bm) {
        var pi = bm.Member;
        pi.SetValue(target, value);
    }
}
...