2016-03-21 47 views
1

嗯,我知道在C#中数组是一个对象 但一些代码混淆了我居然数组的结构是什么?

int[] numbers = {4, 5, 6, 1, 2, 3, -2, -1, 0}; 
foreach (int i in numbers)  
     Console.WriteLine(i); 

在这个循环中它是一种访问访问任意对象int value= object.property;

的任意属性属性,但如何? 和这里的财产本身是什么?他们如何组织?

+5

你的问题有点不清楚;你可以试着重述它吗?问题的标题和您提供的两个代码片段之间似乎没有太多联系。例如,“int value = object.property”与问题或较大的代码片段有什么关系?你对C#中的数组的内部和实现细节有疑问吗?或者你对'foreach'循环语言结构感兴趣吗? –

+2

你有JavaScript背景吗? – usr

+5

这不会访问任何属性,只是遍历一个'IEnumerable '(一个数组实现的接口)并使用foreach循环访问此过程中的每个元素[MSDN] [https://msdn.microsoft.com/deta -at/library/ttw7t8t6.aspx] – derpirscher

回答

0

一个数组只是一个集合,或IEnumerable<T>其中T代表一个特定的类型;你的情况intSystem.Int32

内存分配...

的int是32位长,并且想要的10个项目

int[] numbers = new int[10];

32×10的阵列= 320位内存分配

内存访问...

说你的阵列开始于0000:0000,你要访问的数组的索引n [0-9] ...

伪代码...

index = n 
addressof(n) = 0000:0000 + (sizeof(int) * index) 

index = 2 
addressof(n) = 0000:0000 + (32 * 2) 

这是一个当您访问数组中的每个索引项时会发生什么的简化示例(您的foreach循环是这样做的)

foreach循环通过引用数组中的每个元素来工作(在你的情况下,引用被称为i)。

为什么你不在财产访问...

在阵列中,项目是由指数存储,而不是由名称...

...所以你不能.. 。

numbers.1 
numbers.2 

...但你可以...

numbers[1] 
numbers[2] 

由于每个Ø bject派生自对象,您可以访问特定类型的任意成员...

numbers[1].GetHashCode(); 

实施例:

//Define an array if integers, shorthand (see, memory allocation)... 
int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 

//For each element in the array (under the hood, get the element's address in memory and hold this in a reference called i)... 
foreach(int i in numbers) 
{ 
    // Call GetHashCode() on the instance pointed to by i and pass the reference (by value) to the Console.WriteLine method. 
    Console.WriteLine(i.GetHashCode()); 
} 
+0

我真的很好奇OP的问题是什么。当你说他们“会是对的”时,你是什么意思? –

+0

OP只是想知道如何在不直接访问属性的情况下获得数组的实际值。他只是不明白IEnumerable和c#的“in”功能。 – DiscipleMichael

3

如何数据被存储

基本上阵列是数据的斑点。整数是32位有符号整数的值类型。

C#中的标识符是指向对象的指针或实际值。在引用类型的情况下,它们是真实的指针,在值类型的情况下(例如int,float等),它们是实际的数据。 int是一个值类型,int[](数组到整数)是一个引用类型。

这样工作的原因基本上是“效率”:复制一个值类型的4字节或8字节的开销非常小,而复制整个数组的开销可能非常大。

如果您有一个包含N个整数的数组,它只不过是一个N * 4个字节的数组,其变量指向第一个元素。 blob中没有每个元素的名称。

例如为:

int[] foo = new int[10]; // allocates 40 bytes, naming the whole thing 'foo' 
int f = foo[2]; // allocates variable 'f', copies the value of 'foo[2]' into 'f'. 

访问数据

至于的foreach ...在C#中,所有集合实施一个名为IEnumerable<T>的接口。如果你使用它,编译器会在这种情况下注意到它是一个整型数组,它将遍历所有元素。换句话说:

foreach (int f in foo) // copy value foo[0] into f, then foo[1] into f, etc 
{ 
    // code 
} 

是(在阵列的情况下!)完全相同的事情:

for (int i=0; i<foo.Length; ++i) 
{ 
    int f = foo[i]; 
    // code 
} 

注意,我明确提出“在阵列的情况下”在这里。数组是C#编译器的特例。如果你不使用数组(但是f.ex.与List,Dictionary或更复杂的东西),它的工作原理有点不同,即使用EnumeratorIDisposable。请注意,这只是一个编译器优化,数组完全有能力处理IEnumerable。如果你想有一个名字

你可能需要一个Dictionary

var e = myEnumerable.GetEnumerator(); 
try 
{ 
    while (e.MoveNext()) 
    { 
     var f = e.Current; 
     // code 
    } 
} 
finally 
{ 
    IDisposable d = e as IDisposable; 
    if (d != null) 
    { 
     d.Dispose(); 
    } 
} 

对于那些有兴趣,基本上它会产生这种非阵列和非字符串。

+0

是的,正如你所说的,普通数组X []由编译器专门为'foreach'处理。 (我们知道这是因为在.Net 1.x中存在“foreach”,但在.Net 1.x中不存在“IEnumerable ”。) –

+0

@MatthewWatson嗯,是,不是。是的:在旧风格中,foreach曾经为某些案例施放过。 'foreach(myOldCollection中的字符串s)'这些值被转换为字符串。但是,它也与IL操作码有关,以及编译器可以使用ldlen操作码对字符串和数组进行简单优化 - 在这种情况下,它也不需要检查IDisposable '。 – atlaste

+0

数组如何实现'IEnumerable'和朋友实际上是非常有趣的 - 有很多的运行时黑客入侵它。但就你的代码而言,即使数组类型本身既不是通用的,也不是“真正”实现该接口的'T []'实现'IEnumerable '。烟雾和镜像:) – Luaan