在扩展方法中更改数组的大小不起作用?

时间:2015-01-06 13:07:34

标签: c# arrays concatenation extension-methods concat

所以基本上我为数组类型编写了我的小Add扩展方法。

using System;
using System.Linq;
public static class Extensions 
{
    public static void Add<T>(this T[] _self, T item)
    {
        _self = _self.Concat(new T[] { item }).ToArray();
    }
}
public class Program
{
    public static void Main()
    {
        string[] test = { "Hello" };
        test = test.Concat(new string[] { "cruel" }).ToArray();
        test.Add("but funny");
        Console.WriteLine(String.Join(" ", test) + " world");
    }
}

输出应为Hello cruel but funny world,但but funny永远不会在扩展方法中连接。

在扩展程序中编辑相同的数组似乎也不起作用:

using System;
using System.Linq;
public static class Extensions 
{
    public static void Add<T>(this T[] _self, T item)
    {
        Array.Resize(ref _self, _self.Length + 1);
        _self[_self.Length - 1] = item;
    }
}
public class Program
{
    public static void Main()
    {
        string[] test = { "Hello" };
        test = test.Concat(new string[] { "cruel" }).ToArray();
        test.Add("but funny");
        Console.WriteLine(String.Join(" ", test) + " world");
    }
}

我在这里遇到了什么问题,如何将其用作扩展名?

.dotNet小提琴:https://dotnetfiddle.net/9os8nYhttps://dotnetfiddle.net/oLfwRD

(找到一种方法可以保持通话test.Add("item");

会很棒

3 个答案:

答案 0 :(得分:3)

您正在为参数分配新引用,除非您将其作为ref参数传递,否则它不会更改实际数组。由于这是一种扩展方法,因此不是一种选择。因此,请考虑使用常规方法:

public static void Add<T>(ref T[] _self, T item)
{
    _self = _self.Concat(new T[] { item }).ToArray();
}

Add(ref test, "but funny");

或者如果你坚持使用扩展方法,你需要使用数组第二个参数才能使用ref:

public static void AddTo<T>(this T item, ref T[] arr, )
{
    arr = arr.Concat(new T[] { item }).ToArray();
}

"but funny".AddTo(ref test);

Array.Resize不起作用。因为它更改了_self,而不是test数组。现在,当您传递不带ref关键字的引用类型时,将复制引用。它是这样的:

string[] arr1 = { "Hello" };
string[] arr2 = arr1;

现在,如果您为arr2分配一个新引用,它将不会更改arr1的引用。Array.Resize正在做的是因为无法调整数组大小,所以创建一个新数组并将所有元素复制到一个新数组,并将该新引用分配给参数(在这种情况下为_self)。因此它会更改where _self个点但由于_selftest是两个不同的引用(例如arr1arr2),因此更改其中一个不会影响另一个。

另一方面,如果您将数组作为ref传递给您的方法,就像我的第一个示例一样,Array.Resize也将按预期工作,因为在这种情况下,不会复制引用:< / p>

public static void Add<T>(ref T[] _self, T item)
{
    Array.Resize(ref _self, _self.Length + 1);
    _self[_self.Length - 1] = item;
}

答案 1 :(得分:1)

我相信_self =会将_self对象的副本创建到为参数_self创建的局部变量中 - 因此原始文件不会更新。使用类似列表的引用类型,或创建一个返回新数组的静态方法。

就原因的“感觉”而言:你在一个变量实例上调用一个方法 - 你不能在它的上下文中执行的代码中更改该实例

答案 2 :(得分:-1)

您可以更改以下代码:

public static class Extensions 
{
    public static T[] Add<T>(this T[] _self, T item)
    {
        return _self.Concat(new T[] { item }).ToArray();
    }
}
public class Program
{
    public static void Main()
    {
        string[] test = { "Hello" };
        test = test.Concat(new string[] { "cruel" }).ToArray();
        test = test.Add("but funny");
        Console.WriteLine(String.Join(" ", test) + " world");
    }
}

作为附注 - 使用方法与Concat方法相同。