Does System.Array perform boxing on value types or not?
Asked Answered
P

1

12

I recently did some rough performance measuring on List<> vs [] for an array of small structures. System.Array seemed to win hands down so I went with that.

It's only just dawned on me that System.Array contains object types, so surely filling it with structures would cause boxing to occur?

However, the MSDN entry for System.Array states:

In the .NET Framework version 2.0, the Array class implements the System.Collections.Generic.IList<T>, System.Collections.Generic.ICollection<T>, and System.Collections.Generic.IEnumerable<T> generic interfaces. The implementations are provided to arrays at run time, and therefore are not visible to the documentation build tools. As a result, the generic interfaces do not appear in the declaration syntax for the Array class, and there are no reference topics for interface members that are accessible only by casting an array to the generic interface type (explicit interface implementations).

Does this mean that boxing does not occur after all? (And would explain my performance results)

Phira answered 21/11, 2011 at 15:7 Comment(1)
In order to explain your performance results probably we should see the code you used to measure performance.Relique
C
14

No using an array does not box if you use the indexer notation. e.g.

new int[2];
x=[1]=3;

Compiles to the following IL (note the line numbers are irrelevant as they come from some other snippet of code)

IL_0011: ldc.i4.2
IL_0012: newarr System.Int32
IL_0017: stfld Int32[] x
IL_001c: ldarg.0
IL_001d: ldfld Int32[] x
IL_0022: ldc.i4.1
IL_0023: ldc.i4.3
IL_0024: stelem.i4

For languages that cannot use the indexer (and I don't really know if they exist or not) 2 other methods are created at compile time for Arrays.

It creates these public methods::

public int Get(int index)
public void Set(int index,int value)

Those methods don't box either and are not normally accessible through C#. (Don't ask me why they are public methods). You can execute them using IL or by creating delegates to them. They are slower as you are forced to do a callvirt to invoke these methods.

The stelem.* and ldelem.* family is used to handle storing to a strongly typed array type. When using generics usually the following prefixes are attached constrained or readonly when using a T[]. stelem.* type usually do not check type. E.g. using stelem.i4 is faster than using stelem.any Int32 unless you prefix it with readonly because otherwise it forces a type check.

Now the typecheck is COMPLETELY useless on valuetype arrays are they are not covariant!

Because the runtime generates the one dimensional array starting at zero (either called SZ_array or vector type) type they are natively known.

There are a family of il op codes for them: newarr,stelem.*,ldelem.*,ldlen etc.

The List<T> type uses a T[] for its backing store in the microsoft implementation of the BCL. List<T> does not box. Regardless of using list or array you are storing things in an array.

Czech answered 21/11, 2011 at 16:5 Comment(2)
Here's a supplementary link to another answer regarding heap/stack allocation of arrays and their contained values: #1114319Murr
Since Arrays are reference types, the unboxed int's are stored in the managed heap as well - there's nothing to box about.Charbonnier

© 2022 - 2024 — McMap. All rights reserved.