C# 数组的结构是什么?

C# 数组的结构是什么?,c#,arrays,foreach,C#,Arrays,Foreach,我知道C#中的数组是一个对象 但实际上有一点代码把我弄糊涂了 int[] numbers = {4, 5, 6, 1, 2, 3, -2, -1, 0}; foreach (int i in numbers) Console.WriteLine(i); 访问任意对象的任意属性int value=object.property 在这个循环中,它有点像访问属性,但是如何访问呢? 这里的地产是什么?它们是如何组织的?数组只是一个集合,或者IEnumerable其中T表示特

我知道C#中的数组是一个对象 但实际上有一点代码把我弄糊涂了

int[] numbers = {4, 5, 6, 1, 2, 3, -2, -1, 0};
foreach (int i in numbers)      
        Console.WriteLine(i);
访问任意对象的任意属性
int value=object.property

在这个循环中,它有点像访问属性,但是如何访问呢?
这里的地产是什么?它们是如何组织的?

数组只是一个集合,或者
IEnumerable
其中
T
表示特定类型;在您的情况下,
int
System.Int32

内存分配…

int的长度为32位,您需要一个包含10项的数组

int[]数字=新的int[10]

32 x 10=分配的320位内存

内存访问…

假设你的数组从
0000:0000开始,你想访问数组的索引
n[0-9]

伪代码

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

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

foreach循环通过引用数组中的每个元素来工作(在您的例子中,该引用称为i)

为什么不按属性访问…

在数组中,项是按索引存储的,而不是按名称存储的

。。。所以你不能

numbers.1
numbers.2
…但是你可以

numbers[1]
numbers[2]
由于每个对象都是从对象派生的,所以您可以访问特定类型的任意成员

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());
}

数据的存储方式

基本上,数组是一个数据块。整数是32位有符号整数的值类型

C#中的标识符要么是指向对象的指针,要么是实际值。对于引用类型,它们是实指针;对于值类型(例如int、float等),它们是实际数据
int
是一种值类型,
int[]
(数组到整数)是一种引用类型

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

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

例如:

访问数据

至于foreach。。。在C#中,所有集合都实现一个名为
IEnumerable
的接口。如果您使用它,编译器将在本例中注意到它是一个整数数组,它将遍历所有元素。换言之:

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
}
如果你想要一个名字


你可能需要一本
字典

你的问题有点不清楚;你能再说一遍吗?问题的标题和您提供的两个代码片段之间似乎没有太多联系。例如,
int value=object.property
与问题或更大的代码段有什么关系?您是否对C#中数组的内部结构和实现细节有疑问,或者您是否对
foreach
循环语言构造感兴趣?您是否有JavaScript背景?这不会访问任何属性,只会迭代
IEnumerable
(数组实现的接口)并使用foreach循环[MSDN]访问此过程中的每个元素[我认为您对属性是什么感到困惑。数组中的数字不是属性。例如,属性就是数组长度。foreach在数组中所做的是在引擎盖下创建for循环。如果它不是数组,而是列表或字典,它将创建哈希集并实现GetEnumerator(),并使用MoveNext()和Current()来枚举集合。@derpirscher实际上不是这样。
foreach
用于数组(和字符串)编译为true for循环,不涉及
IEnumerable
中的枚举数。在验证时,它可能会检查它的存在,但我甚至对此表示怀疑。在这里,您可以自己看看发生了什么:;查看IL——那里没有枚举数。不过,在较高的级别上,您对它的作用是正确的。是的,正如您所说,普通数组X[]是由编译器专门为
foreach
处理的(我们知道这一点是因为
foreach
存在于.Net 1.x中,但
IEnumerable
不存在于.Net 1.x中)。@MatthewWatson好的,是和否。是:在旧样式中,foreach用于对某些情况进行强制转换。
foreach(myOldCollection中的字符串s)
将值强制转换为字符串。但是,这也与IL操作码和编译器可以进行的琐碎优化有关(对于
字符串和数组)使用
ldlen
操作码-在这种情况下,它也不需要检查
IDisposable
。数组的
foreach
IEnumerable
之间的一个很大区别是,为后者生成的IL代码将调用
IEnumerator.GetEnumerator()
IEnumerator.MoveNext()
,而前者不进行任何此类调用(因此速度更快)。数组与数组的IL反编译代码foreach示例:
Print1()
Print2()
生成完全相同的IL代码。作为旁注,非数组类型的
foreach
欺骗并使用duck类型作为可枚举的主要源,而不是
IEnumerable
/
IEnumerable
。例如,我真的很好奇OP的问题是什么。当你说他们“是对的”时,你是什么意思?OP只是想知道如何在不直接访问属性的情况下获得数组的实际值。他只是不理解IEnumerable和c#的“in”功能。
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
}
var e = myEnumerable.GetEnumerator();
try
{
    while (e.MoveNext())
    {
        var f = e.Current;
        // code
    }
}
finally
{
    IDisposable d = e as IDisposable;
    if (d != null)
    {
        d.Dispose();
    }
}