从.ToArray()引用修改原始值类型IEnumerable

时间:2014-04-23 00:50:27

标签: c# .net arrays linq

基本上我试图用一个通用数组包装一个IEnumerable并且仍然能够修改原始集合中的值,当我只修改它们的内部字段时,这适用于引用类型,但是在使用时值类型或尝试替换它似乎不起作用的元素。

例如:

// Original enumerable
var test = new List<int>(new int[] {
    1,
    2,
    3
});

// Array wrapper
var test2 = test.ToArray();
test2[0] = 100; // Does not change test[0]

// Don't want to use pointers, but as a test
unsafe
{
    int* test3 = &test2[0];
    *test3 = 100; // Still does not change test[0]
}

所以我想知道是否有某种方法可以创建一个值类型IEnumerable的数组包装器,它允许修改原始集合值?

我需要这样做的原因是类与FORTRAN95代码共享,并且由于对.NET数组的有限编译器支持,我不能从System.Array继承任何内容

1 个答案:

答案 0 :(得分:3)

Enumerable.ToArray()没有&#34;包裹&#34;数组中的可枚举:它遍历可枚举,创建一个数组。它几乎相当于:

public static T[] ToArray<T>( this IEnumerable<T> source )
{
  List<T> list = new List<T>() ;

  foreach( T item in source )
  {
    list.Add(item) ;
  }

  T[] value = list.ToArray() ;
  return value ;
}

所以如果你做这样的事情:

int[] foo = PopulateSource() ;
int[] bar = foo.ToArray()    ; // Enumerable.ToArray()

foo[3] = int.MinValue ;
无论数组是否包含值类型或引用类型,

都不会影响bar[3]

但是,如果您使用参考类型,

Widget[] foo = PopulateSource() ;
Widget[] bar = foo.ToArray()    ; // Enumerable.ToArray()

并说出类似

的内容
foo[3].Gadget = new Gadget("Pancake Turner") ;

然后更改将反映在foo[3]bar[3]中,因为两个数组插槽都是对同一Widget实例的引用。

此外,您无法在数组中包装内容,因为即使System.Array不是sealed

public abstract class Array :
  ICloneable, IList, ICollection, IEnumerable,
  IStructuralComparable, IStructuralEquatable

它是一个特殊的类,不能继承。所以像这样:

class Widget : System.Array
{
}

产生此编译器错误

error CS0644: 'ConsoleApplication2.Program.Widget' cannot derive from special class 'System.Array'

您可以做的是为原始对象创建一个包装器,它提供类似于数组的语义,实现IListIList<T>