C# 将扩展 Append 方法添加到 class 类型 T 数组

C# Add extension Append method to class array of type T

使用这个answer to the question "How to add a string to a string[] array? There's no .Add function" I am trying to use this answer to write an generic extension to append elements to an generic array. Only using the Array.Resize() method works well and the sample below adds an extra element to my string array

string[] array = new string[] { "Foo", "Bar" };
Array.Resize(ref array, array.Length + 1);
array[array.Length - 1] = "Baz";

但是当我尝试使用下面描述的 ArrayExtension 方法时,方法 在方法内调整我的数组大小,但是当它 return 时数组没有改变?

我的分机class

public static class ArrayExtensions
{
    public static void Append<T>(this T[] array, T append)
    {
        Array.Resize(ref array, array.Length + 1);
        array[array.Length - 1] = append;    // < Adds an extra element to my array
    }
}

使用如下

string[] array = new string[] { "Foo", "Bar" };
array.Append("Baz");

方法returns时,添加的元素不存在。我错过了什么?

更新

如前所述,此问题已在此处提出和回答过。我将接受上一个问题“”作为我问题的答案。

更新 2

因为如果在扩展方法中使用 return 方法,它确实违反了框架中类似 classes 的预期行为,即 Append() 修改对象本身,我做了一些更改扩展方法以防止其被错误使用。感谢@NineBerry 指出这一点。

我还添加了 params T[] add 以允许一次添加多个元素。

public static class ArrayExtensions
{
    /// <summary>
    /// Creates a copy of an object array and adds the extra elements to the created copy
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="array"></param>
    /// <param name="add">Elemet to add to the created copy</param>
    /// <returns></returns>
    public static T[] CopyAddElements<T>(this T[] array, params T[] add)
    {
        for (int i = 0; i < add.Length; i++)
        {
            Array.Resize(ref array, array.Length + 1);
            array[array.Length - 1] = add[i];
        }
        return array;
    }
}

用法

string[] array = new string[] { "Foo", "Bar" };
array = array.CopyAddElements("Baz", "Foobar");
for (int i = 0; i < array.Length; i++)
{
    System.Console.Write($"{array[i]} ");
}

/* Output
 *  Foo Bar Baz Foobar
*/

Array.Resize 创建一个新数组。这就是为什么您必须使用 ref 关键字将数组传递给 Array.Resize。因此,从 Array.Resize 返回后,变量 array 引用了不同的对象。

无法使用扩展方法来完成您想要做的事情。

为什么不简单地使用 List<> 而不是数组?使用 Array.Resize 是一项非常昂贵的操作。这意味着每次调用它以增加数组长度时,分配新内存并将数据从旧数组复制到新数组。

与您的直觉相反,this 参数未通过隐式 ref 传递,也不允许向其添加 ref。另见讨论 here

实际发生的是

array.Append("Baz");

翻译成

ArrayExtensions.Append( array, "Baz" );

这意味着对 array 的引用由 value 传入,因此在 Append 方法中您使用 copy参考Array.Resize 方法然后将这个新变量作为 ref,在内存中创建一个 新数组 并将变量更改为指向它。不幸的是,只改变了这个变量,而不是原来的

您可以 return 新创建的数组作为 return 值,或者创建一个使用 ref 而不是扩展方法的静态方法。