如何从属性名称构建LINQ键选择器委托?

时间:2016-01-17 14:54:08

标签: c# linq lambda delegates

通常在提供用户指定的排序顺序并使用LINQ进行排序时,我最终会得到一个像这样的丑陋场景:

public static IEnumerable<ConfirmationItemViewModel> SortAscending(IEnumerable<ConfirmationItemViewModel> confirmations, string sortProperty)
{
    switch (sortProperty)
    {
        case "CreatedOn":
            confirmations = confirmations.OrderBy(i => i.CreatedOn).ToList();
            break;
        case "PaymentId":
            confirmations = confirmations.OrderBy(i => i.PaymentId).ToList();
            break;
        default:
            confirmations = confirmations.OrderBy(i => i.PaymentId).ThenBy(i => i.CreatedOn).ToList();
            break;
    }
    return confirmations;
}

OrderBy方法接受类型为Func<TSource, TKey>的函数委托,我认为它用于从正在排序的集合中的每个项目中获取sort属性的值。我想编写一个方法来获取属性名称而不是委托,并返回一个返回属性值的委托,如果这甚至一半解释了我的意思。

希望我尝试对其进行编码,但这不会起作用。鉴于我对表达式和代表的理解有限,这是我能够得到的最接近的:

public static Func<TObject, TKey> BuildKeySelector<TObject, TKey>(TObject source, string propertyName)
{
    return obj =>
    {
        var prop = source.GetType().GetProperty(propertyName, typeof(TKey));
        return (TKey) prop.GetValue(obj);
    };
}

static void Main(string[] args)
{
    // Sort a list of Person objects by their Name property.
    var peeps = new List<Person>();
    var rank = peeps.OrderBy(BuildKeySelector(<something>, "Name"));
}

1 个答案:

答案 0 :(得分:1)

您不需要TObject object作为参数。如果您发现只使用source来获取类型,则会变得清晰。

以下是如何做到这一点:

public static Func<TObject, TKey> BuildKeySelector<TObject, TKey>(string propertyName)
{
    return obj =>
    {
        var prop = typeof(TObject).GetProperty(propertyName, typeof(TKey));
        return (TKey) prop.GetValue(obj);
    };
}

但是,这不是非常有效,因为您的函数(从BuildKeySelector方法返回的委托)每次都会使用反射来获取属性值。一种更好的方法是构建一个表达式(可以缓存)并将表达式编译为委托。