Int [] là kiểu tham chiếu hay kiểu giá trị?


124

Tôi biết một int là một loại giá trị, nhưng các mảng của các loại giá trị là gì? Các loại tham khảo? Các loại giá trị? Tôi muốn chuyển một mảng đến một hàm để kiểm tra một cái gì đó. Tôi có nên vượt qua mảng không, vì nó sẽ chỉ chuyển tham chiếu của nó, hay tôi nên chuyển nó dưới dạng ref?


11
Trong tương lai, bạn có thể kiểm tra xem một cái gì đó được truyền bằng tham chiếu hoặc bằng giá trị bằng cách tạo một biến, chuyển biến đó vào một phương thức thay đổi biến đó và kiểm tra xem giá trị của biến đó là gì sau khi nó chạy qua phương thức. Nếu nó giống nhau, nó được truyền theo giá trị, khác nhau, được truyền bằng tham chiếu.

11
@ darkassassin93: Truyền theo tham chiếu hoặc theo giá trị không liên quan đến việc một cái gì đó là loại tham chiếu hay loại giá trị. (Các loại giá trị có thể được truyền bằng tham chiếu và các loại tham chiếu có thể được truyền theo giá trị.)
LukeH

2
Trong hầu hết các trường hợp nếu bạn có thể lưu trữ [null] bên trong một trường hoặc biến, bạn có thể cho rằng đó là loại ref. Các ngoại lệ chắc chắn là các loại nullable (Nullable <int> hoặc int?) Cũng như các chuỗi.
Noel Widmer

3
@ NoëlWidmer Chuỗi không phải là một ngoại lệ: chúng là loại ref.
Arthur Castro

2
@ArthurCastro Tranh luận tới 50%: chuỗi kế thừa từ lớp có nghĩa là chúng là các kiểu tham chiếu. Tuy nhiên, sự bình đẳng của họ dựa trên danh tính (so sánh giá trị) chứ không phải tham chiếu và hành vi vượt qua của họ được ghi đè để phù hợp với hành vi của các loại giá trị. Về cơ bản, chúng là các loại tham chiếu theo định nghĩa nhưng hoạt động giống như các loại giá trị theo cách thực hiện.
Noel Widmer

Câu trả lời:


201

Mảng là các cơ chế cho phép bạn coi một số mục là một bộ sưu tập duy nhất. Microsoft® .NET Common Language Runtime (CLR) hỗ trợ các mảng một chiều, các mảng đa chiều và các mảng lởm chởm (mảng của các mảng). Tất cả các kiểu mảng được bắt nguồn từ System.Array, chính nó có nguồn gốc từ System.Object. Điều này có nghĩa là tất cả các mảng luôn là các kiểu tham chiếu được phân bổ trên heap được quản lý và biến ứng dụng của bạn chứa tham chiếu đến mảng chứ không phải chính mảng đó.

https://msdn.microsoft.com/en-us/l Library / bb985948.aspx


54
Các loại giá trị kế thừa từ System.ValueType, chính nó kế thừa từ System.Object. Vì vậy, chỉ vì Array xuất phát từ System.Object không có nghĩa đó là loại tham chiếu. Điều khiến System.Array trở thành một kiểu tham chiếu là các thể hiện của nó được sao chép bởi tham chiếu. IOW, tập trung vào thực tế rằng System.Array là một lớp. Đó là những gì làm cho nó một loại tài liệu tham khảo.
P.Brian.Mackey

8
<nitpick> Tôi biết có thể có vẻ như tài liệu này ngụ ý rằng System.Array xuất phát từ System.Object làm cho nó trở thành một loại tham chiếu. Mặc dù có thể không đúng khi bất kỳ loại nào xuất phát từ System.Object là loại tham chiếu, ngoại lệ duy nhất cho quy tắc này là System.ValueType, được trình biên dịch xử lý khác nhau. </ Nitpick>
Yannick Mippi

Liên kết trên bị hỏng. Đây là một liên kết msDN khác cho thấy hệ thống phân cấp thừa kế của System.Array: msdn.microsoft.com/de-de/l
Library / system.array (v = vs.110) .aspx

Bất cứ thứ gì xuất phát từ System.Object đều là kiểu tham chiếu, UNLESS nó cũng xuất phát từ System.ValueType. @ P.Brian.Mackey chỉ vì một loại là một lớp không có nghĩa đó là loại tham chiếu, bởi vì đằng sau hậu trường, các cấu trúc chỉ là các lớp xuất phát từ System.ValueType.
David Klempfner

31

Thử nghiệm đơn giản nhất cho loại tham chiếu so với loại giá trị là loại tham chiếu có thể null, nhưng loại giá trị thì không thể.


46
... ngoại trừ các loại giá trị null, là nullable (bạn có thể đặt giá trị thành null, có nghĩa là giá trị null cho loại chứ không phải là tham chiếu null ) và vẫn là loại giá trị.
Jon Skeet

1
Không bao giờ nghĩ làm điều đó khi cố gắng hiểu liệu chúng có phải là loại giá trị hay không! Ý tưởng tuyệt vời.
nuốt chửng elysium


6

Đầu tiên tôi muốn nói với bạn rằng Array là một kiểu tham chiếu. Tại sao? Tôi giải thích ném một ví dụ ở đây.

Thí dụ:

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.

Ngoài ra các loại tham chiếu có thể là null trong khi các loại giá trị thì không thể.

loại giá trị được lưu trữ trong Stack và loại tham chiếu được lưu trữ trong Heap

Bạn có thể truyền mảng cho hàm bằng cách sử dụng out hoặc ref. Chỉ có phương thức khởi tạo là khác nhau.

hơn..


3

Kiểm tra để xác minh xem đó là loại tham chiếu hoặc giá trị:

// 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!
//**************************

Bạn có thể kiểm tra trực tuyến: https://dotnetfiddle.net/UWFP45


2
Nó sẽ dễ dàng hơn để tạo ra một mảng và cố gắng gán nó thành null. Quá trình biên dịch sẽ thất bại nếu đó là một loại giá trị ..
elysium nuốt chửng

Được cảnh báo trước. Khi C # 8 được phát hành, nó cũng sẽ thất bại nếu bạn đang sử dụng tính năng loại tham chiếu nullable vì các loại tham chiếu không thể null cũng không thể chấp nhận null.
Đánh dấu A. Donohoe

2

Bản thân mảng là một kiểu tham chiếu. Các giá trị của mảng đó là các giá trị hoặc kiểu tham chiếu được xác định bởi kiểu dữ liệu mảng. Trong ví dụ của bạn, mảng là kiểu tham chiếu và các giá trị là kiểu giá trị.

Tất cả các mảng một chiều ngầm thực hiện IList<T>, đây <T>là kiểu dữ liệu của mảng. Thay vào đó, bạn có thể sử dụng giao diện đó làm kiểu dữ liệu của tham số phương thức của mình. Bạn cũng có thể sử dụng IEnumerable<T>cho kiểu dữ liệu. Trong cả hai trường hợp (hoặc ngay cả khi bạn chỉ sử dụng int[]), bạn không cần phải vượt qua nó một cách rõ ràng như một reftham số.


0

// Tham chiếu đến mảng được truyền bằng giá trị. Đây là nguồn gốc của sự nhầm lẫn :-) ...

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

0

Mảng luôn là kiểu tham chiếu. Nó không quan trọng mảng sẽ chứa kiểu giá trị như kiểu int hoặc kiểu tham chiếu như chuỗi. Khi bạn khai báo mảng chẳng hạn

int[] integers=new int[10];

Biến số nguyên tự nó chỉ chứa tham chiếu đến mảng sẽ nằm trong heap.

Ngoài ra có nhiều người đề cập rằng bạn có thể khác loại giá trị với loại tham chiếu chỉ phụ thuộc vào thực tế biến đó có thể là null hay không. Tôi muốn đề cập rằng trong các loại giá trị hiện tại c # cũng có thể là null

ví dụ

int? integer=null

và nó không phải là cách tốt để xác định loại là tham chiếu hoặc giá trị chỉ phụ thuộc vào biến thực tế có thể là null hoặc không.


-2

Chỉ cần một chút hiểu biết:

Ví dụ: intđại diện cho một số nguyên duy nhất, int[]đại diện cho một mảng các số nguyên.

Để khởi tạo mảng với các kích thước cụ thể, bạn có thể sử dụng newtừ khóa, đưa ra kích thước trong dấu ngoặc vuông sau tên loại:

//create a new array of 32 ints.
int[] integers = new int[32];

Tất cả các mảng là các loại tham chiếu và theo ngữ nghĩa tham chiếu. Do đó, trong mã này, mặc dù các phần tử riêng lẻ là các loại giá trị nguyên thủy, integersmảng là một kiểu tham chiếu. Vì vậy, nếu sau này bạn viết:

int[] copy = integers;

điều này chỉ đơn giản là gán toàn bộ bản sao biến để tham chiếu đến cùng một mảng, nó sẽ không tạo ra một mảng mới.

Cú pháp mảng của C # rất linh hoạt, nó cho phép bạn khai báo các mảng mà không cần khởi tạo chúng để mảng có thể được kích thước động sau này trong chương trình. Với kỹ thuật này, về cơ bản, bạn đang tạo một tham chiếu null và sau đó trỏ tham chiếu đó vào một vị trí bộ nhớ được phân bổ động được yêu cầu với một newtừ khóa:

int[] integers;
integers = new int[32];

Cảm ơn bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.