如何使用表达式基于继承的接口属性

时间:2015-05-22 18:28:54

标签: c# expression-trees

这个问题已经在这个问题中得到了一定程度的讨论:Create Generic Expression from string property name但也许我错过了答案,或者它有些微妙的不同。

我有以下可查询的扩展方法:

public static IQueryable<TSource> OrderByPropertyDescending<TSource>(IQueryable<TSource> source, string propertyName)
    {
        var sourceType = typeof (TSource);
        var parameter = Expression.Parameter(sourceType, "item");
        var orderByProperty = Expression.Property(parameter, propertyName);
        var orderBy = Expression.Lambda(orderByProperty, new[] { parameter });
        return Queryable.OrderByDescending(source, (dynamic) orderBy);
    }

出于这个问题的目的,让我们假设可查询源实例有一个名为&#39; Created&#39;这是一种DateTime。如果我们定义一个具有“创建”属性的类。在它上面然后OrderByDescending然后上面的工作正常。 e.g。

var queryable = new List<EntityClassWithCreatedProperty>().AsQueryable();
var result = queryable.OrderByPropertyDescending("Created").ToList();

如果我们做同样的事情,但使用ICreated等具有Created属性的界面:

public interface ICreated
{
    DateTime Created { get; }
}

然后以下内容也有效:

var queryable = new List<ICreated>().AsQueryable();
var result = queryable.OrderByPropertyDescending("Created").ToList();

但是,如果您具有以下界面层次结构:

public interface ITimestamped : ICreated
{
     ...
}

然后以下将失败:

var queryable = new List<ITimestamped>().AsQueryable();
var result = queryable.OrderByPropertyDescending("Created").ToList();

使用与其他问题类似的错误消息:Instance property&#39; Created&#39;没有为ITimestamped类型定义。我假设我需要在声明类型的接口上找到属性(我可以通过爬行源类型来完成)但是我该怎么做呢?我尝试过的大多数尝试都会导致不正确的原始源类型无法转换回IQueryable。我是否需要在某处使用ConvertType调用?感谢。

1 个答案:

答案 0 :(得分:1)

我会使用另一个带有propertyInfo的Expression.Property()方法,例如

public static IQueryable<TSource> OrderByPropertyDescending<TSource>(IQueryable<TSource> source, string propertyName)
{
    var sourceType = typeof (TSource);
    var parameter = Expression.Parameter(sourceType, "item");
    var propertyInfo = FindMyProperty(sourceType, propertyName);
    var orderByProperty = Expression.Property(parameter, propertyInfo);
    var orderBy = Expression.Lambda(orderByProperty, new[] { parameter });
    return Queryable.OrderByDescending(source, (dynamic) orderBy);
}

private static PropertyInfo FindMyProperty(Type type, string propertyName)
{
    return type.GetProperty(propertyName);
}

此时你的问题与表达无关,这是一个简单的反思问题,你必须找到获得所需属性的正确方法。这里有很多场景。对于您的确切一个,意味着从父接口获取属性,您可以执行以下操作:

private static PropertyInfo FindMyProperty(Type type, string propertyName)
{
    var result = type.GetProperty(propertyName);
    if (result == null)
    {
        foreach(var iface in type.GetInterfaces())
        {
            var ifaceProp = FindMyProperty(iface, propertyName);
            if (ifaceProp != null)
                return ifaceProp;
        }

    }
    return result;
}

声明! 这绝不是从类型中获取属性的最佳方法,但它应该适用于您的情况。你应该谷歌找到满足你所有要求的FindMyProperty实现:)