Ответ 1
Возьмите тип выражения (первый) и скажите
Expression<Func<C, string>> c = x => x.B;
Type paramType = c.Parameters[0].Type; // first parameter of expression
var d = paramType.GetMember((c.Body as MemberExpression).Member.Name)[0];
У меня проблема, которую я не ожидал. Пример, вероятно, иллюстрирует мой вопрос лучше, чем абзац:
ОБНОВЛЕНО: переход к последнему кодовому блоку для более красноречивого примера кода.
public class A
{
public string B { get; set; }
}
public class C : A { }
Вот код из метода:
var a = typeof(C).GetMember("B")[0];
var b = typeof(A).GetMember("B")[0];
Expression<Func<C, string>> c = x => x.B;
var d = (c.Body as MemberExpression).Member;
Ниже приведены результаты некоторых сравнений:
a == b //false
a == d //false
b == d //true
Первые два несколько неожиданны. Я понимаю, что хотя B не является виртуальным, C может определять свойство с тем же именем с помощью оператора w new
, но в этом случае я этого не делал.
Второй действительно самый удивительный для меня (и является сердцем моей проблемы). Несмотря на то, что параметр для лямбда четко определен как тип типа C, он все равно возвращает его, как если бы свойство было доступно из базового класса.
То, что я ищу, - это способ получить MemberInfo из выражения лямбда, как если бы я использовал отражение типа параметра, чтобы получить MemberInfo. Мой проект по существу хранит MemberInfos в словаре по своему усмотрению, и он должен иметь функциональность, где вы можете получить доступ к элементам, предоставив выражение лямбда.
Повторенный пример кода Дэнни Чена
public class Base
{
public string Name { get; set; }
}
public class Derived : Base { }
//in Main
var parentMember = typeof(Base).GetMember("Name")[0];
var childMember = typeof(Derived).GetMember("Name")[0];
Expression<Func<Base, string>> parentExp = x => x.Name;
var parentExpMember = (parentExp.Body as MemberExpression).Member;
Expression<Func<Derived, string>> childExp = x => x.Name;
var childExpMember = (childExp.Body as MemberExpression).Member;
parentMember == childMember //false, good
parentMember == parentExpMember //true, good
childMember == childExpMember //false, why?
Возьмите тип выражения (первый) и скажите
Expression<Func<C, string>> c = x => x.B;
Type paramType = c.Parameters[0].Type; // first parameter of expression
var d = paramType.GetMember((c.Body as MemberExpression).Member.Name)[0];
То, что я ищу, - это способ получить MemberInfo из выражения лямбда, как если бы я использовал отражение типа параметра, чтобы получить MemberInfo.
Это не сервис, который преобразовывал дерево выражений в lambdas для обеспечения. Если вы собираетесь использовать функцию "off label", вы можете не получить желаемые результаты.
Целью деревьев выражений является предоставление семантического анализа выражения компилятору выражения в форме, пригодной для анализа во время выполнения, а не времени компиляции с целью создания объектов запроса, которые могут быть удалены в базы данных.
Правильный семантический анализ компилятора заключается в том, что Name объявляется как свойство Base и вызывается в экземпляре Derived, так что именно информация, которую вы получаете из полученного дерева выражений.
Хороший вопрос. Я использую некоторые другие имена, чтобы сделать их более ясными.
public class Base
{
public string Name { get; set; }
}
public class Derived : Base { }
//in Main
var parentMember = typeof(Base).GetMember("Name")[0];
var childMember = typeof(Derived).GetMember("Name")[0];
Expression<Func<Base, string>> parentExp = x => x.Name;
var parentExpMember = (parentExp.Body as MemberExpression).Member;
Expression<Func<Derived, string>> childExp = x => x.Name;
var childExpMember = (childExp.Body as MemberExpression).Member;
parentMember == childMember //false, good
parentMember == parentExpMember //true, good
childMember == childExpMember //false, why?
При отладке вы найдете childExpMember.ReflectedType
is Base
, а childMember.ReflectedType
- Derived
. AFAIK DeclaringType
показывает, где объявлен член, а ReflectedType
показывает, где элемент отражен (из-за наследования/переопределения/etc). Так что Я думаю, что это ошибка (официального подтверждения).
Я считаю, что вам нужно передать флаг "FlattenHierarchy" в параметр bindingAttr GetMember.
Из MSDN:
Указывает, что должны быть возвращены общедоступные и защищенные статические члены в иерархии. Частные статические члены в унаследованных классах не возвращаются. Статические члены включают поля, методы, события и свойства. Вложенные типы не возвращаются.