我知道int是一个值类型,但是什么是值类型数组?参考类型?价值类型?我想将一个数组传递给一个函数来检查一些东西。我应该只是传递数组,因为它只是传递它的引用,或者我应该将它传递给ref?
答案 0 :(得分:179)
数组是允许你的机制 将几件物品作为单一物品处理 采集。 Microsoft®.NETCommon 语言运行时(CLR)支持 一维数组, 多维数组和锯齿状 数组(数组数组)。所有阵列 类型是隐式派生的 System.Array,它本身就是派生的 来自System.Object。这意味着 所有数组始终是引用类型 哪些是在托管上分配的 堆,您的应用程序的变量包含 对数组的引用而不是 数组本身。
答案 1 :(得分:26)
参考类型与值类型的最简单测试是引用类型可以是null
,但值类型不能。
答案 2 :(得分:14)
数组(甚至像int这样的值类型)是C#中的引用类型。
http://msdn.microsoft.com/en-us/library/aa288453(VS.71).aspx:
在C#中,数组实际上是对象。 System.Array是所有数组类型的抽象基类型。
答案 3 :(得分:6)
首先,我想告诉您Array是一种引用类型。为什么?我在这里解释一个例子。
示例:强>
int val = 0; // this is a value type ok
int[] val1 = new int[20] // this is a reference type because space required to store 20 integer value that make array allocated on the heap.
参考类型也可以为null,而值类型可以为
value type stored in Stack and reference type stored in Heap
您可以使用out或ref将数组传递给函数。只有初始化方法不同。
答案 4 :(得分:2)
数组本身是引用类型。该数组的值是由数组数据类型确定的值或引用类型。在您的示例中,数组是引用类型,值是值类型。
所有单维数组都隐式实现IList<T>
,其中<T>
是数组的数据类型。您可以使用该接口作为方法参数的数据类型。您还可以使用IEnumerable<T>
作为数据类型。在任何一种情况下(或者即使您只使用int[]
),您也不需要将其明确地作为ref
参数传递。
答案 5 :(得分:2)
测试以验证它是否为引用或值类型:
// we create a simple array of int
var a1 = new int[]{1,2,3};
// copy the array a1 to a2
var a2 = a1;
// modify the first element of a1
a1[0]=2;
// output the first element of a1 and a2
Console.WriteLine("a1:"+a1[0]); // 2
Console.WriteLine("a2:"+a2[0]); // 2
//**************************
// all the two variable point to the same array
// it's reference type!
//**************************
您可以在线测试:https://dotnetfiddle.net/UWFP45
答案 6 :(得分:1)
我想补充一下其他答案,尽管int []是引用类型,但随着C#中stackalloc
的引入,您可以将堆栈中的数组分配为值类型。这可能会提高性能,因为将数组放置在堆栈中会降低GC的压力(顺便说一句,一般而言,谈论值类型时,您可能经常会听到值类型在堆栈中分配;这并不总是正确的:
https://docs.microsoft.com/en-us/archive/blogs/ericlippert/the-truth-about-value-types):
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/stackalloc
stackalloc表达式在堆栈上分配一个内存块。一种 在方法执行期间创建的堆栈分配的内存块是 该方法返回时自动丢弃。你不能 显式释放用stackalloc分配的内存。一叠 分配的内存块不受垃圾收集和 不必固定使用固定的语句。
stackalloc
用法示例:
Span<int> numbers = stackalloc int[10];
for (int ctr = 0; ctr < numbers.Length; ctr++)
numbers[ctr] = ctr + 1;
foreach (int i in numbers)
Console.WriteLine(i);
使用此技术不要忘记有限的堆栈内存。链接https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/stackalloc提供了有关如何安全考虑到此限制的stackalloc
使用必要信息。
此外,这是一个讨论stackalloc
:Practical use of `stackalloc` keyword
答案 7 :(得分:0)
//对数组的引用按值传递。这是混乱的根源:-) ...
int[] test = { 1, 2, 3, 4 };
modifContenuSansRef(test);
Console.WriteLine(test[0]); // OK --> 99 le contenu du tableau est modifié
modifTailleSansRef(test);
Console.WriteLine(test.Length); // KO --> 4 La taille n'est pas modifiée
}
static void modifContenuSansRef(int[] t)
{
t[0] = 99;
}
static void modifTailleSansRef(int[] t)
{
Array.Resize(ref t, 8);
}
答案 8 :(得分:0)
数组总是引用类型。无关紧要数组包含像int这样的值类型或像string这样的引用类型。当你声明数组时,例如
int[] integers=new int[10]
;
整数变量本身只包含对将驻留在堆中的数组的引用。
还有很多人提到你可以将值类型与引用类型区别开来,这取决于变量可能为null的事实。 我想提一下,在c#中当前值类型也可以为null
例如
int? integer=null
并不是识别类型是引用或值的好方法,只取决于事实变量是否为空。
答案 9 :(得分:-2)
只是一点见解:
例如,int
表示单个整数,int[]
表示整数数组。
要初始化具有特定维度的数组,您可以使用new
关键字,在类型名称后面的方括号中给出大小:
//create a new array of 32 ints.
int[] integers = new int[32];
所有数组都是引用类型,并遵循引用语义。因此,在此代码中,即使单个元素是原始值类型,integers
数组也是引用类型。所以,如果你以后写:
int[] copy = integers;
这将简单地指定整个变量副本来引用同一个数组,它不会创建新的数组。
C#的数组语法非常灵活,它允许您在不初始化数组的情况下声明数组,以便稍后可以在程序中动态调整数组的大小。使用这种技术,您基本上创建了一个空引用,然后将该引用指向使用new
关键字请求的动态分配的内存位置:
int[] integers;
integers = new int[32];
谢谢。