【问题标题】:How can I get an extension method to change the original object?如何获得更改原始对象的扩展方法?
【发布时间】:2010-02-24 14:37:39
【问题描述】:

我希望能够编写扩展方法,这样我就可以说:

lines.ForceSpaceGroupsToBeTabs();

代替:

lines = lines.ForceSpaceGroupsToBeTabs();

但是,当前输出的代码如下:

....one
........two

代替:

Tone
TTtwo

我必须在以下代码中进行哪些更改才能使其输出:

Tone
TTtwo

(请注意,为了可见性,. = space, T = \t):

using System;
using System.Collections.Generic;

namespace TestExtended82343
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> lines = new List<string>();
            lines.Add("....one");
            lines.Add("........two");

            lines.ForceSpaceGroupsToBeTabs();

            lines.ForEach(l => Console.WriteLine(l));
            Console.ReadLine();
        }
    }

    public static class Helpers
    {
        public static void ForceSpaceGroupsToBeTabs(this List<string> originalLines)
        {
            string spaceGroup = new String('.', 4);
            List<string> lines = new List<string>();
            foreach (var originalLine in originalLines)
            {
                lines.Add(originalLine.Replace(spaceGroup, "T"));
            }
            originalLines = lines;
        }
    }
}

【问题讨论】:

    标签: c# generics object extension-methods


    【解决方案1】:

    您必须修改传递给扩展方法的List&lt;string&gt; 的内容,而不是保存对列表的引用的变量:

    public static void ForceSpaceGroupsToBeTabs(this List<string> lines)
    {
        string spaceGroup = new String('.', 4);
        for (int i = 0; i < lines.Count; i++)
        {
            lines[i] = lines[i].Replace(spaceGroup, "T");
        }
    }
    

    【讨论】:

    • 确实如此。不能切换“扩展”引用的对象,但是可以改变一个的内容
    【解决方案2】:

    您必须更改原始列表的 内容 - 仅将参数重新分配为具有不同的值是行不通的。像这样的:

    public static void ForceSpaceGroupsToBeTabs(this List<string> lines)
    {
        string spaceGroup = new String('.', 4);
        for (int i = 0; i < lines.Count; i++)
        {
            lines[i] = lines[i].Replace(spaceGroup, "T");
        }
    }
    

    值得注意的是,这与扩展方法无关。想象一下你刚刚打电话:

    Helpers.ForceSpaceGroupsToBeTabs(lines);
    

    ...因为这就是代码被有效翻译成的内容。它是一种扩展方法,这并没有什么特别之处。如果您更改代码以便“正常”静态方法可以工作,那么它也可以作为扩展方法工作。正如 cmets 中所述,您不能使用扩展方法做的一件事是将第一个参数设为 ref 参数。

    (编辑:我意识到这与 dtb 发布的代码完全相同,尽管我们是独立到达那里的。无论如何我都会保留这个答案,因为它不仅仅是代码。)

    【讨论】:

    • 这不是完全相同的代码,你有 spaceGroup("T"),你是在想别的东西还是只是一个错字(它不能编译)
    • @Jon:不同之处在于,使用 Helpers.ForceSpaceGroupsToBeTabs 他可以将参数更改为“ref”参数,在这种情况下,他现有的代码具有所需的影响。但是,使用扩展方法,您不能使参数引用...
    • @Edward:只是一个错字。会修复的。
    【解决方案3】:

    如果它是引用类型,则必须更改其内容。如果它是您传入的值类型,那么您就不走运了。扩展方法的存在是为了支持 C# 中的函数范式,而这些函数范式就其本质而言,倾向于类型的不变性,因此无法更改调用扩展方法的值。

    换句话说,虽然你可以这样做,但它可能不符合函数式编程的“精神”。

    【讨论】:

    • 我认为这个答案的第二部分具有误导性。扩展方法的压倒性用例是在接口上,它们是引用类型,在这些情况下,对变异没有特殊限制:功能与普通方法相同,因为 a.SomeMethod(); 不能使 a 引用其他东西, 但可以更改它所引用的对象。
    猜你喜欢
    • 1970-01-01
    • 2012-05-03
    • 1970-01-01
    • 2015-03-09
    • 2011-02-04
    • 1970-01-01
    • 2012-06-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多