Expression for Type members results in different Expressions (MemberExpression, UnaryExpression)

后端 未结 2 625
时光说笑
时光说笑 2020-12-03 00:55

Description

I have a expression to point on a property of my type. But it does not work for every property type. \"Does not mean\" means it result in different exp

相关标签:
2条回答
  • 2020-12-03 01:26

    The reason this happens is that Age is a value type. In order to coerce an expression returning a value type into Func<Person,object> the compiler needs to insert a Convert(expr, typeof(object)), a UnaryExpression.

    For strings and other reference types, however, there is no need to box, so a "straight" member expression is returned.

    If you would like to get to the MemberExpression inside the UnaryExpression, you can get its operand:

    private static MemberExpression GetMemberExpression<T>(
        Expression<Func<T,object>> exp
    ) {
        var member = exp.Body as MemberExpression;
        var unary = exp.Body as UnaryExpression;
        return member ?? (unary != null ? unary.Operand as MemberExpression : null);
    }
    
    0 讨论(0)
  • 2020-12-03 01:27

    Rather than comparing the Member.Name string, I would suggest comparing the PropertyInfo instances directly for equality, in order to avoid false positives when two properties in distinct classes share the same name.

    public static bool IsSameProperty<TSourceA, TSourceB, TPropertyA, TPropertyB>(
        Expression<Func<TSourceA, TPropertyA>> expA,
        Expression<Func<TSourceB, TPropertyB>> expB)
    {
        MemberExpression memExpA = expA.Body as MemberExpression;
        MemberExpression memExpB = expB.Body as MemberExpression;
    
        if (memExpA == null || memExpB == null)
            return false;
    
        PropertyInfo propA = memExpA.Member as PropertyInfo;
        PropertyInfo propB = memExpB.Member as PropertyInfo;
    
        if (propA == null || propB == null)
            return false;
    
        return propA.Equals(propB);
    }
    

    You can ensure that your lambda expression is compiled as a MemberExpression rather than a UnaryExpression simply by specifying the correct value type (rather than object) as the generic type TResult of your Expression<Func<T, TResult>> expression.

    Expression<Func<Person, int>> expression1 = x => x.Age;
    Expression<Func<Person, int>> expression2 = x => x.Age;
    Expression<Func<Person, string>> expression3 = x => x.Name;
    
    Console.WriteLine(IsSameProperty(expression1, expression2));   // True
    Console.WriteLine(IsSameProperty(expression1, expression3));   // False
    
    0 讨论(0)
提交回复
热议问题