Я пытаюсь использовать ExpressionVisitor, чтобы получить переопределенный член выражения, но он дает мне базовый . Что мне здесь не хватает?

В следующем примере воспроизводится это поведение:

Простые базовые и производные типы:

class Base
{
    public virtual string Property { get; set; }
}

class Derived : Base
{
    public override string Property { get; set; }
}

Я использую это выражение посетитель:

internal class DemoVisitor : ExpressionVisitor
{
    private MemberInfo _member;

    public static MemberInfo GetMemberInfo(LambdaExpression expression)
    {
        var visitor = new DemoVisitor();
        visitor.Visit(expression);

        return visitor._member;
    }

    protected override Expression VisitMember(MemberExpression node)
    {
        // invalid member here
        //node.Member.DeclaringType.Name.Dump();
        _member = _member ?? node.Member;

        return base.VisitMember(node);
    }
}

Называя это так

void Main()
{
    var derived = new Derived();
    var expression = (Expression<Func<string>>)(() => derived.Property);
    DemoVisitor.GetMemberInfo(expression).DeclaringType.Name.Dump();
}

Это возвращает Base вместо Derived. Что мне нужно сделать, чтобы получить доступ к замещенному участнику?

Мне нужна, потому что я читаю его атрибуты позже, и в настоящее время он дает мне атрибуты свойства на базовом классе вместо полученного.

1
t3chb0t 14 Окт 2018 в 15:51

1 ответ

Лучший ответ

Что касается вашего другого вопроса о том, какой член посещается: посещаются все используемые члены в вашем выражении, то есть все методы, свойства и поля, тогда как node.Member возвращает либо MemberExpression, derived, либо {{X2} } объект, который все является производным от {{X3}}.

Поэтому ваш посетитель должен вернуть оба (здесь я использовал ValueTuple):

internal class DemoVisitor : ExpressionVisitor
{
    private Type type;
    private MemberInfo _member;

    public static (Type, MemberInfo) GetMemberInfo(LambdaExpression expression)
    {
        var visitor = new DemoVisitor();
        visitor.Visit(expression);

        return (visitor.type, visitor._member);
    }

    protected override Expression VisitMember(MemberExpression node)
    {
        if (_member == null)
        {
          _member = node.Member;
          type = node.Expression.Type;
        }

        return base.VisitMember(node);
    }
}

Что касается вашего другого вопроса о том, какой член посещается: посещаются все используемые члены в вашем выражении, то есть все методы, свойства и поля, тогда как node.Member возвращает либо MethodInfo, PropertyInfo, либо {{X2} } объект, который все является производным от MemberInfo.

1
ckuri 14 Окт 2018 в 13:25