I stumbled on the fact that the indexer this[int index] { get; }
works differently for an array of structs than it does for a List of structs. Namely, that the indexer in the case of an T[]
returns a reference to the element within the array whereas the indexer in the case of a List<T>
returns a copy of the element.
This is a very big semantic and performance difference, and I'm glad that T[]
allows us to work around the performance limitation of List<T>
.
However, I'm puzzled by the actual implementation. The code for Array
in the .net reference sources reads thus:
Object IList.this[int index] {
get { return GetValue(index); }
set { SetValue(value, index); }
}
Where GetValue
is defined as follows:
public unsafe Object GetValue(int index)
{
if (Rank != 1)
throw new ArgumentException(Environment.GetResourceString("Arg_Need1DArray"));
Contract.EndContractBlock();
TypedReference elemref = new TypedReference();
InternalGetReference(&elemref, 1, &index);
return TypedReference.InternalToObject(&elemref);
}
The return type of the indexer is Object
, implying that boxing will take place.
So my question is, can I be certain that no boxing will occur when I access an element of a T[]
where T
is a struct?
I assume that the compiler and/or CLR treat Array specially, and don't actually bother with the signature of the indexer. Is this correct? Is there a fuller discussion of this somewhere?
Namely, that the indexer in the case of an T[] returns a reference to the element within the array
Not really. It's more that there isn't an indexer for arrays - instead an element-access expression represents an array access instead of an element access (sections 7.6.6.1 and 7.6.6.2 of the C# 5 spec respectively).
There's a very significant difference between these two - in particular, an array access is classified as a variable, whereas an indexer access is classified as a value.
It's very similar to the difference between a property and a field - they both have the same syntax for access, but a property invokes a function member and returns a value, whereas a field access just yields the variable.
So my question is, can I be certain that no boxing will occur when I access an element of a
T[]
whereT
is a struct?
If you're accessing it as a T[]
, sure. The indexer you looked at is only used when you're viewing the array as an IList
. So if you use:
IList array = new int[2];
object x = array[0];
then yes, that'll box the value... but if you write
int[] array = new int[2];
int x = array[0];
then that won't, and it won't be accessing that indexer code or the GetValue
method at all.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With