Я думаю, что вижу то, что вы пытаетесь - одно расширение 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);
}
}