2017-02-23 76 views
1

的类阵列采用这种answer问题“How to add a string to a string[] array? There's no .Add function”我试图用this answer编写一个通用的扩展附加元素添加到generic array。仅使用Array.Resize()方法效果好,下面的示例中增加了一个额外的元素,以我的string arrayC#添加扩展Append方法将T型

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

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

UPDATE

正如指出的那样,这个问题已经被问和之前在这里找到答案。我将接受上一个问题“Changing size of array in extension method does not work?”作为我的问题的答案。

更新2

,因为如果在扩展方法用于返回方法它不违反该追加()来修改对象本身,我做了一些改动框架类似的类的预期行为扩展方法来防止它被错误地使用。感谢@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 
*/ 
+0

Array.Resize是一种欺骗。这实际上是一个新对象的副本。从那里,你需要一个ref参数对实际参数产生影响。 –

回答

4

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

没有办法使用扩展方法来做你正在做的事情。

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

+0

请提出'列表'您的答案的第一句话。这是真正的解决方案。 –

2

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

4

实际情况是什么

array.Append("Baz"); 

被翻译成

ArrayExtensions.Append(array, "Baz"); 

这意味着参考array传递,所以Append方法内您可以使用参考文献的副本。然后Array.Resize方法将这个新变量作为ref,在内存中创建一个新阵列并将变量更改为指向它。不幸的是,这个只改变了这个变量而不是原来的那个

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