【问题标题】:How can I build a LINQ key selector delegate from a property name? [duplicate]如何从属性名称构建 LINQ 键选择器委托? [复制]
【发布时间】:2016-01-17 14:54:07
【问题描述】:

通常在提供用户指定的排序顺序并使用 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&lt;TSource, TKey&gt; 类型的函数委托,我认为它用于从正在排序的集合中的每个项目中获取排序属性的值。我想编写一个采用属性名称而不是委托的方法,并返回一个返回属性值的委托,如果这能解释我的意思的话。

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

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

【问题讨论】:

  • 您遇到了什么错误?你在哪里调用 SortAscending?
  • 你不需要TObject object作为参数。
  • 是的,谢谢,@YacoubMassad,我意识到虽然我在为使我的代码工作而苦苦挣扎,但现在我发现我寻求的方法是不必要的。我会在几分钟内删除这个问题,因为它是重复的。

标签: c# linq lambda delegates


【解决方案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 方法返回的委托)每次都会使用反射来获取属性值。更好的方法是构建一个表达式(您可以缓存)并将该表达式编译成一个委托。

【讨论】:

  • 非常正确,谢谢。唯一的不便是必须指定对象和属性类型,例如var rank = peeps.OrderBy(BuildKeySelector&lt;Person, string&gt;("Name"));,但我想可怜的编译器无法推断出仅在方法内部确定的属性的类型。
猜你喜欢
  • 1970-01-01
  • 2020-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多