【问题标题】:Extension method not updating object passed in扩展方法不更新传入的对象
【发布时间】:2009-01-11 22:53:16
【问题描述】:

我最近开始学习 LINQ,偶然发现了OrderBy 扩展方法。这最初让我很兴奋,因为它的语法似乎比我们在通用列表中到处使用的 Sort 方法要好得多。

例如,在对语言列表进行排序时,我们通常会这样做:

neutralCultures.Sort((x, y) => x.EnglishName.CompareTo(y.EnglishName));

这很好用,但我更喜欢OrderBy 的语法,它只要求您传入您希望排序的属性,如下所示:

neutralCultures.OrderBy(ci => ci.EnglishName);

问题是OrderBy 返回IOrderedEnumerable,但我需要List<T>。因此,我开始使用与 OrderBy 相同的签名来扩展 SortList<T> 方法。

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 不起作用。

【问题讨论】:

    标签: c# .net linq


    【解决方案1】:

    我之前使用选择器编写过排序变体 - 这并不难......类似于:

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

    【讨论】:

    • 请注意,添加一个接受 IComparer&lt;TValue&gt; 以支持自定义比较器的重载非常简单。
    【解决方案2】:

    这是我所期望的行为。想象一下,如果这样的事情是可能的:

    var c = myCustomer;
    myCustomer.DoStuff();
    if (c == myCustomer) // returns false!!!
    

    仅调用对象上的方法(对于框架的用户来说,扩展方法看起来就是这样)不应更改引用指向的实例。

    对于你的例子,我会坚持排序。

    【讨论】:

    • 注意这个推理只适用于类;结构 can 的行为与您所说的完全一样,即使它们是不可变的。 DoStuff() 方法(用于结构)可以是this = new Foo("mwahahaha");
    • 谢谢马特,现在更有意义了。感谢您为我简化它。
    【解决方案3】:

    我认为这是因为 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);
        }
    

    【讨论】:

    • 好主意,但我只是尝试添加“ref”关键字,它不适用于“this”。
    • 不,我认为你做不到。
    • 非常感谢。这正是我接下来要做的事情。
    【解决方案4】:

    您正在替换名为 list 的局部参数变量的值,而不是更改调用者变量的值(这是您正在尝试做的事情。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-29
      • 2015-05-08
      • 2011-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多