Czy int [] jest typem odniesienia czy typem wartości?


124

Wiem, że int jest typem wartości, ale jakie są tablice typów wartości? Typy referencyjne? Typy wartości? Chcę przekazać tablicę do funkcji, aby coś sprawdzić. Czy powinienem przekazać tablicę, ponieważ po prostu przekaże jej odniesienie, czy powinienem przekazać ją jako ref?


11
W przyszłości możesz sprawdzić, czy coś jest przekazywane przez odwołanie, czy przez wartość, tworząc zmienną, przekazując tę ​​zmienną do metody, która zmienia tę zmienną i sprawdzając, jaka jest wartość tej zmiennej po jej uruchomieniu przez metodę. Jeśli jest taki sam, jest przekazywany przez wartość, inny, przekazywany przez odwołanie.

11
@ darkassassin93: przekazywanie przez odwołanie lub przez wartość nie ma związku z tym, czy coś jest typem referencyjnym, czy typem wartości. (Typy wartości można przekazywać przez odwołanie, a typy odwołań przez wartość.)
LukeH

2
W większości przypadków, jeśli możesz przechowywać [null] wewnątrz pola lub zmiennej, możesz założyć, że jest to typ ref. Wyjątkami są z pewnością typy dopuszczające wartość null (Nullable <int> lub int?), A także ciągi.
Noel Widmer

3
Ciągi @ NoëlWidmer nie są wyjątkiem: są to typy referencyjne.
Arthur Castro

2
@ArthurCastro Argree do 50%: ciągi dziedziczą z klasy, co oznacza, że ​​są typami referencyjnymi. Jednak ich równość opiera się na tożsamości (porównywaniu wartości), a nie na odwołaniu, a ich przebieg jest zastępowany, aby pasował do zachowania typów wartości. Zasadniczo są to typy referencyjne z definicji, ale pod względem implementacji zachowują się bardziej jak typy wartości.
Noel Widmer

Odpowiedzi:


201

Tablice to mechanizmy, które pozwalają traktować kilka elementów jako jedną kolekcję. Środowisko wykonawcze języka wspólnego języka Microsoft® .NET (CLR) obsługuje tablice jednowymiarowe, tablice wielowymiarowe i tablice postrzępione (tablice tablic). Wszystkie typy tablic są niejawnie wyprowadzane z System.Array, który sam pochodzi z System.Object. Oznacza to, że wszystkie tablice są zawsze typami odwołań, które są przydzielane na zarządzanym stercie, a zmienna aplikacji zawiera odwołanie do tablicy, a nie do samej tablicy.

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


54
Typy wartości dziedziczą po System.ValueType, który sam dziedziczy po System.Object. Zatem tylko dlatego, że Array pochodzi od System.Object, nie oznacza, że ​​jest to typ referencyjny. To, co sprawia, że ​​System.Array jest typem referencyjnym, polega na tym, że jego instancje są kopiowane przez odwołanie. IOW, skoncentruj się na fakcie, że System.Array jest klasą. To sprawia, że ​​jest to typ referencyjny.
P.Brian. Mackey,

8
<nitpick> Wiem, że może to wyglądać tak, jakby dokumentacja sugerowała, że ​​System.Array pochodzący z System.Object czyni go typem referencyjnym. Chociaż może nie być prawdą, że każdy typ wywodzący się z System.Object jest typem referencyjnym, jedynym wyjątkiem od tej reguły jest System.ValueType, który jest inaczej traktowany przez kompilator. </nitpick>
Yannick Motton,

Powyższy link jest uszkodzony. Oto kolejne łącze msdn, które pokazuje hierarchię dziedziczenia System.Array: msdn.microsoft.com/de-de/library/system.array(v=vs.110).aspx
MUG4N

Wszystko, co pochodzi od System.Object, jest typem referencyjnym, JEŚLI nie pochodzi również od System.ValueType. @ P.Brian.Mackey tylko dlatego, że typ jest klasą, nie oznacza, że ​​jest to typ referencyjny, ponieważ za kulisami struktury są po prostu klasami, które pochodzą od System.ValueType.
David Klempfner

31

Najprostszym testem dla typu referencyjnego w porównaniu z typem wartości jest to, że typy referencyjne mogą być null, ale typy wartości nie mogą.


46
... z wyjątkiem typów wartości dopuszczających wartość null, które dopuszczają wartość null (można ustawić wartość na null, co oznacza wartość null dla typu zamiast odwołania o wartości null ) i nadal są typami wartości.
Jon Skeet

1
Nigdy nie myślałem o tym, próbując zrozumieć, czy są to typy wartości, czy nie! Świetny pomysł.
pożarł elysium


6

Najpierw chcę wam powiedzieć, że Array jest typem referencyjnym. Czemu? Wyjaśniam, podam tutaj jeden przykład.

Przykład:

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.

Również typy odwołań mogą mieć wartość null, podczas gdy typy wartości nie mogą.

typ wartości przechowywany w stosie i typ odniesienia przechowywany w sterty

Możesz przekazać array do funkcji za pomocą out lub ref. Tylko metody inicjalizacji są różne.

więcej..


3

Przetestuj, aby sprawdzić, czy jest to odwołanie, czy typ wartości:

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

Możesz to przetestować online: https://dotnetfiddle.net/UWFP45


2
Po prostu byłoby łatwiej utworzyć tablicę i spróbować przypisać ją do wartości null. Kompilacja zakończyłaby się niepowodzeniem, gdyby była to typ wartości ...
pożarł elysium

Bądź ostrzeżony. Po wydaniu C # 8 zakończy się również niepowodzeniem, jeśli używasz funkcji typów odwołań dopuszczających wartość null, ponieważ typy odwołań nie dopuszczające wartości null nie mogą również akceptować wartości null.
Mark A. Donohoe

2

Sama tablica jest typem referencyjnym. Wartości tej tablicy są wartościami lub typami odwołań określonymi przez typ danych tablicy. W Twoim przykładzie tablica jest typem referencyjnym, a wartości są typami wartości.

Wszystkie tablice jednowymiarowe implementują niejawnie IList<T>, gdzie <T>jest typem danych tablicy. Zamiast tego można użyć tego interfejsu jako typu danych parametru metody. Możesz również użyć IEnumerable<T>dla typu danych. W żadnym przypadku (lub nawet jeśli po prostu używasz int[]) nie powinieneś jawnie przekazywać tego jako refparametru.


0

// Odniesienie do tablicy jest przekazywane przez wartość. To jest źródło zamieszania :-) ...

        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

Tablice zawsze są typami referencyjnymi. Nie ma znaczenia tablica zawierałaby typ wartości, taki jak int, lub typ referencyjny, taki jak string.

int[] integers=new int[10];

Sama zmienna integers zawiera tylko odniesienie do tablicy, która będzie znajdować się w stercie.

Wiele osób wspomina również, że typ wartości może różnić się od typu referencyjnego, po prostu zależy to od tego, czy zmienna może być pusta, czy nie. Chciałbym wspomnieć, że w c # obecnie typach wartości również może być null

na przykład

int? integer=null

i nie jest dobrym sposobem na identyfikację typu jako odniesienia lub wartości zależy tylko od tego, czy zmienna faktów może mieć wartość null lub nie.


-2

Trochę wglądu:

Na przykład intreprezentuje pojedynczą liczbę całkowitą, int[]reprezentuje tablicę liczb całkowitych.

Aby zainicjować tablicę o określonych wymiarach, możesz użyć newsłowa kluczowego, podając rozmiar w nawiasach kwadratowych po nazwie typu:

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

Wszystkie tablice są typami odwołań i są zgodne z semantyką odwołań. Dlatego w tym kodzie, mimo że poszczególne elementy są pierwotnymi typami wartości, integerstablica jest typem referencyjnym. Więc jeśli później napiszesz:

int[] copy = integers;

spowoduje to po prostu przypisanie całej kopii zmiennej w celu odniesienia się do tej samej tablicy, ale nie utworzy nowej tablicy.

Składnia tablic w języku C # jest elastyczna, pozwala na deklarowanie tablic bez ich inicjowania, dzięki czemu można dynamicznie zmieniać rozmiar tablicy w dalszej części programu. Za pomocą tej techniki w zasadzie tworzysz odwołanie zerowe, a później wskazujesz to odwołanie na dynamicznie przydzielony odcinek lokalizacji pamięci żądany za pomocą newsłowa kluczowego:

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

Dziękuję Ci.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.