如何使用表达式根据继承的接口对集合进行排序 属性

How to use expressions to sort a collection based on an inherited interface property

这个问题已经在这个问题中进行了一定程度的讨论: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);
    }

为了这个问题的目的,让我们假设可查询源实例有一个名为 'Created' 的 属性,它是一种 DateTime。如果我们定义一个 class 上面有 属性 'Created' 然后 OrderByDescending 然后上面的将工作正常。例如

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();

与另一个问题的错误消息类似:未为类型 ITimestamped 定义实例 属性 'Created'。我假设我需要在接口的声明类型上找到 属性(我可以通过爬取源类型来做到这一点)但是我该如何处理它呢?我尝试过的大多数尝试都会导致不正确的原始源类型无法转换回 IQueryable。我需要在某处使用 ConvertType 调用吗?谢谢。

我会使用另一种 Expression.Property() 方法,它接受 属性Info,例如

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;
}

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