C#将扩展追加方法添加到类型为T的类数组中

时间:2017-02-23 09:29:50

标签: c# arrays generics append extension-methods

将此answer用于问题“ How to add a string to a string[] array? There's no .Add function ”我正在尝试使用this answer编写通用扩展名以将元素追加到{{3 }}。只使用generic array方法效果很好,下面的示例为我的Array.Resize()添加了一个额外的元素

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

但是当我尝试使用下面描述的ArrayExtension方法时,方法会调整方法中的数组,但是当它返回时,数组是否保持不变?

我的扩展课程

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

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

更新

正如所指出的,这个问题之前已经被问到并回答过了。我会接受上一个问题“string array”作为我问题的答案。

更新2

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

我还添加了Changing size of array in extension method does not work?以允许一次添加多个元素。

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
*/

3 个答案:

答案 0 :(得分:4)

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

无法使用扩展方法来执行您要执行的操作。

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

答案 1 :(得分:4)

实际发生的是

array.Append("Baz");

翻译为

ArrayExtensions.Append( array, "Baz" );

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

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

答案 2 :(得分:2)

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