具有属性继承的表达式树会导致参数异常

Ada*_*oll 4 .net linq expression-trees

关注这篇文章:链接文本我正在尝试创建一个引用属性属性的表达式树.我的代码看起来像这样:

public interface IFoo
{
    void X {get;set;}
}

public interface IBar : IFoo
{
    void Y {get;set;}
}

public interface IFooBarContainer
{
    IBar Bar {get;set;}
}

public class Filterer
{
     //Where T = "IFooBarContainer"
     public IQueryable<T> Filter<T>(IEnumerable<T> collection)
     {
              var argument = Expression.Parameter(typeof (T), "item");

              //...

               //where propertyName = "IBar.X";
               PropertyOfProperty(argument, propertyName); 
     }

        private static MemberExpression PropertyOfProperty(Expression expr, string propertyName)
        {
            return propertyName.Split('.').Aggregate<string, MemberExpression>(null, (current, property) => Expression.Property(current ?? expr, property));
        }
}
Run Code Online (Sandbox Code Playgroud)

我收到例外:

System.ArgumentException:没有为类型'IBar'定义实例属性'X'

ReSharper将上面链接中的代码转换为我的示例中的精简语句.这两种形式的方法都返回相同的错误.

如果我引用IBar.Y该方法不会失败.

Tho*_*que 8

您尝试访问的属性不是 IBar.X,它是IFoo.X.该Expression.Property方法需要声明属性的实际类型,而不是子类型.如果您不相信,请尝试:

var prop = typeof(IBar).GetProperty("X");
Run Code Online (Sandbox Code Playgroud)

它返回null(只是因为它IBar是一个接口;它适用于一个类)

我认为使其工作的最简单方法是创建一个帮助方法来解析实际属性,方法是递归地向上移动类型层次结构:

private PropertyInfo GetProperty(Type type, string propertyName)
{
    PropertyInfo prop = type.GetProperty(propertyName);
    if (prop == null)
    {
        var baseTypesAndInterfaces = new List<Type>();
        if (type.BaseType != null) baseTypesAndInterfaces.Add(type.BaseType);
        baseTypesAndInterfaces.AddRange(type.GetInterfaces());
        foreach(Type t in baseTypesAndInterfaces)
        {
            prop = GetProperty(t, propertyName);
            if (prop != null)
                break;
        }
    }
    return prop;
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以PropertyOfProperty按如下方式重写:

private static MemberExpression PropertyOfProperty(MemberExpression expr, string propertyName)
{
    return propertyName
               .Split('.')
               .Aggregate<string, MemberExpression>(
                   expr,
                   (current, property) =>
                       Expression.Property(
                           current,
                           GetProperty(current.Type, property)));
}
Run Code Online (Sandbox Code Playgroud)