Consider following two data types:
class C
{
public int I { get; set; }
}
struct S
{
public int I { get; set; }
}
Let's try to use them inside the list, for example:
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
As expected, there is compilation error on line (a)
: CS1612 Cannot modify the return value of 'List<UserQuery.S>.this[int]' because it is not a variable
. This is fine, because actually we trying to modify temporary copy of S
, which is r-value in giving context.
But let's try to do same thing for an array:
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)
And.. this works.
But
var s_arr_list = (IList<S>) s_arr;
s_arr_list[0].I++;
will not compile, as expected.
If we look at the produced IL, we will find following:
IL_0057: ldloc.1 // s_arr
IL_0058: ldc.i4.0 // index
IL_0059: ldelema UserQuery.S // manager pointer of element
ldelema
loads address of the array element to the top of the evaluation stack. Such behavior is expected with fixed
array and unsafe pointers. But for safe context this is a bit unexpected. Why there is a special unobvious case for arrays? Any why there is no option to achieve same behavior for members of other types?
ldelema
unexpected for safe context? It loads a managed reference (therefore controlled by the GC), likeldloca
orldflda
. When you useref
in C#, this is exactly it. – Vagal