我最近开始了解LINQ并遇到了OrderBy
扩展方法。这最初让我很兴奋,因为语法似乎比我们在通用列表中使用的Sort
方法更好。
例如,在对语言列表进行排序时,我们通常会执行以下操作:
neutralCultures.Sort((x, y) => x.EnglishName.CompareTo(y.EnglishName));
这很好用,但我更喜欢OrderBy
的语法,它只需要传入你想要排序的属性,如下所示:
neutralCultures.OrderBy(ci => ci.EnglishName);
问题是OrderBy
会返回IOrderedEnumerable
,但我需要List<T>
。因此,我开始使用与Sort
相同的签名来扩展List<T>
OrderBy
方法。
public static void Sort<TSource, TKey>(this List<TSource list, Func<TSource, TKey> keySelector)
{
list = list.OrderBy(keySelector).ToList<TSource>();
}
这将被称为:
neutralCultures.Sort(ci => ci.EnglishName);
也许我忽略了一个简单的实现细节,但是这段代码不起作用。它编译,但不返回有序列表。我确信我可以重构它以使其工作,但我只是想知道为什么在扩展方法中设置list
不起作用。
答案 0 :(得分:3)
我之前使用选择器编写了Sort变体 - 这并不难......类似于:
using System;
using System.Collections.Generic;
class Foo
{
public string Bar { get; set; }
}
static class Program
{
static void Main()
{
var data = new List<Foo> {
new Foo {Bar = "def"},
new Foo {Bar = "ghi"},
new Foo {Bar = "abc"},
new Foo {Bar = "jkl"}
};
data.Sort(x => x.Bar);
foreach (var item in data)
{
Console.WriteLine(item.Bar);
}
}
static void Sort<TSource, TValue>(
this List<TSource> source,
Func<TSource, TValue> selector)
{
var comparer = Comparer<TValue>.Default;
source.Sort((x,y) => comparer.Compare(selector(x), selector(y)));
}
}
答案 1 :(得分:2)
我认为这是因为list
没有被ref传递。因此,将list
变量设置为另一个对象不会改变原始变量指向的位置。
您可以这样做(尚未正确测试):
public static void Sort<TSource, TKey>(this List<TSource> list, Func<TSource, TKey> keySelector)
{
var tempList = list.OrderBy(keySelector).ToList<TSource>();
list.Clear();
list.AddRange(tempList);
}
答案 2 :(得分:2)
这就是我期望的行为。想象一下,如果这样的事情是可能的:
var c = myCustomer;
myCustomer.DoStuff();
if (c == myCustomer) // returns false!!!
简单地调用对象上的方法(这是框架用户的扩展方法)不应该更改引用所指向的实例。
对于你的例子,我会坚持使用Sort。
答案 3 :(得分:0)
您正在替换名为list
的本地参数变量的值,而不是更改调用者变量的值(这是您要执行的操作。)