关注这篇文章: link text我正在尝试创建一个引用属性属性的表达式树.我的代码看起来像这样: public interface IFoo{ void X {get;set;}}public interface IBar : IFoo{ void Y {get;set;}}public interface IFooBarC
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)); } }
我收到例外:
System.ArgumentException: Instance
property ‘X’ is not defined for type
‘IBar’
ReSharper将上面链接中的代码转换为我的示例中的精简语句.这两种形式的方法都返回相同的错误.
如果我引用IBar.Y,该方法不会失败.
您尝试访问的属性不是IBar.X,它是IFoo.X. Expression.Property方法需要声明属性的实际类型,而不是子类型.如果您不相信,请尝试:var prop = typeof(IBar).GetProperty("X");
它返回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; }
然后,您可以按如下方式重写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))); }