Rozważmy następujące dwa rodzaje danych:Co różnica między indekser tablicy i wszelkich innych obiektów indekser
class C
{
public int I { get; set; }
}
struct S
{
public int I { get; set; }
}
Spróbujmy wykorzystać je wewnątrz listy, na przykład:
var c_list = new List<C> { new C { I = 1 } };
c_list[0].I++;
var s_list = new List<S> { new S { I = 1 } };
s_list[0].I++; // (a) CS1612 compilation error
Zgodnie z oczekiwaniami, istnieje jest błąd kompilacji na linii (a)
: CS1612 Cannot modify the return value of 'List<UserQuery.S>.this[int]' because it is not a variable
. Jest to w porządku, ponieważ w rzeczywistości próbujemy zmodyfikować tymczasową kopię S
, która jest wartością r w kontekście kontekstu.
Ale spróbujmy zrobić to samo na tablicy:
var c_arr = new[] { new C { I = 1 } };
c_arr[0].I++;
var s_arr = new[] { new S { I = 1 } };
s_arr[0].I++; // (b)
.. I to działa.
Ale
var s_arr_list = (IList<S>) s_arr;
s_arr_list[0].I++;
nie będzie kompilować, jak oczekiwano.
Jeśli spojrzymy na produkowanej IL, znajdziemy następujące:
IL_0057: ldloc.1 // s_arr
IL_0058: ldc.i4.0 // index
IL_0059: ldelema UserQuery.S // manager pointer of element
ldelema
ładuje adres elementu tablicy na szczycie stosu oceny. Takie zachowanie jest oczekiwane z tablicą fixed
i niebezpiecznymi wskaźnikami. Ale dla bezpiecznego kontekstu jest to nieco nieoczekiwane. Dlaczego istnieje specjalny nieoczywisty przypadek dla tablic? Dlaczego nie ma opcji osiągnięcia takiego samego zachowania dla członków innych typów?
Dlaczego uważasz, że 'ldelema' jest nieoczekiwany w kontekście bezpiecznym? Ładuje zarządzaną referencję (w związku z tym kontrolowaną przez GC), taką jak 'ldloca' lub' ldflda'. Kiedy używasz 'ref' w C#, to jest właśnie to. – IllidanS4