【问题标题】:How to use expressions to sort a collection based on an inherited interface property如何使用表达式根据继承的接口属性对集合进行排序
【发布时间】:2015-05-22 18:28:54
【问题描述】:

这个问题已经在一定程度上讨论了这个问题: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 的一种类型。如果我们定义一个具有“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 定义。我假设我需要在声明类型的接口上找到属性(我可以通过爬取源类型来做到这一点),但是我该怎么处理它呢?我尝试过的大多数尝试都导致不正确的原始源类型无法转换回 IQueryable。我需要在某处使用 ConvertType 调用吗?谢谢。

【问题讨论】:

    标签: c# expression-trees


    【解决方案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 实现:)

    【讨论】:

    • 您先生,绝对是个天才,您成就了我的一天!工作得很好,我会按照你的建议研究一种获取房产信息的“好”方式。
    • 很高兴能帮上忙 :)
    猜你喜欢
    • 2011-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多