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

本文关键字:属性 集合 排序 接口 表达式 何使用 继承 | 更新日期: 2023-09-27 17:50:24

这个问题已经在一定程度上讨论过了:从字符串属性名称创建泛型表达式,但也许我错过了答案,或者它是微妙的不同。

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

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类型。如果我们定义一个类,在它上面有属性'Created',然后是orderbydescent,那么上面的工作就会很好。例如

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

与另一个问题类似的错误消息:实例属性'Created'没有为类型ITimestamped定义。我假设我需要在接口的声明类型上找到属性(我可以通过爬行源类型来实现),但是我该怎么做呢?我尝试过的大多数尝试都导致不正确的原始源类型不能被转换回IQueryable。我需要在某个地方使用ConvertType调用吗?谢谢。

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

我将使用另一个接受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的实现,满足您的所有需求:)