扩展方法不更新传入的对象

时间:2009-01-11 22:53:16

标签: c# .net linq

我最近开始了解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不起作用。

4 个答案:

答案 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的本地参数变量的值,而不是更改调用者变量的值(这是您要执行的操作。)