SoFunction
Updated on 2025-03-07

About C# dynamic boxing

Preface

A few days ago, I saw a classmate in the technical group discussing whether dynamic will have the problem of packing and unboxing. My first idea at that time was "will". As for why many people have this question, it is mainly because they thinkdynamicProbably because it's a little special, because it's calledDynamic Type, It may be because of the misunderstanding caused by the dynamics here, and it is believed that the dynamics here can infer specific types, so packing and unboxing can be avoided. But this is not the case. Let’s discuss this issue together today.

Packing and unboxing

First, let’s take a look at what is packing and unboxing. This can be seen in the Boxing and Unboxing documents in Microsoft’s official documents. Let’s briefly summarize the relevant description.

Boxing is the process of converting a value type to a type object or any interface type implemented by this value type. When the common language runtime (CLR) boxs a value type, it wraps the value in the instance and stores it on the managed heap. Unboxing extracts value types from the object. Boxing is implicit; unboxing is clear. The concepts of boxing and unboxing are the basis of a unified view of the C# type system, where any type of value can be considered an object.

It will be more abstract when translated. Understand it is to use the boxing and unboxing functions to link the value type with the reference type by allowing any value of the value type to be converted with the value of the Object type. That is, the value type and reference type are converted to bridge each other, but the problem is also obvious that instances will have problems copying each other before the stack, and there will be certain performance problems, so this has always been a criticism.

Although this is the case, there is no need to keep turning the corners. After all, many times the program has not been confused to this level, because there will be certain problems in various methods or operations in any language. Therefore, the essence is not the various problems in the language, but the question of how to use it in what scenario. For example, the method of avoiding packing and unboxing is what the concept says, that is, avoiding the conversion between value types and reference types, but it is often unavoidable, so there is no need to worry about it.

Explore the essence

The above explains aboutPacking and unboxingNext, let’s define a piece of code to see the effect. For the sake of comparison, let’s compare and take a look directly

dynamic num = 123;
dynamic str = "a string";

If you want to see the essence clearly, you still need to decompile the generated results and take a look at it. Here we can use itILSpyordnSpyLet's take a look at the effect of decompilation

private static void <Main>$(string[] args)
{
	object num = 123;
	object str = "a string";
	();
}

Because I am using the top declaration method of .net6, it will be generated<Main>$method. However, it can be seen from the decompilation resultsThe essence of dynamic is objectIf you still have some doubts, you can view the generatedILCode or useILSpytool

.method private hidebysig static 
	void '&lt;Main&gt;$' (
		string[] args
	) cil managed 
{
	// Method begins at RVA 0x2094
	// Header size: 12
	// Code size: 30 (0x1e)
	.maxstack 1
	.entrypoint
	.locals init (
        // Here we can see that the declared num and str variables are both object types		[0] object num,
		[1] object str
	)

	// object obj = 123;
	IL_0000: ldc. 123
    //The box here indicates that there is a box operation	IL_0002: box []System.Int32
	IL_0007: stloc.0
	// object obj2 = "a string";
	IL_0008: ldstr "a string"
	IL_000d: stloc.1
	// ();
	IL_000e: call valuetype [] []::ReadKey()
	IL_0013: pop
	// (no C# code)
	IL_0014: nop
	IL_0015: nop
	IL_0016: nop
	IL_0017: nop
	IL_0018: nop
	IL_0019: nop
	IL_001a: nop
	IL_001b: nop
	// }
	IL_001c: nop
	IL_001d: ret
} // end of method Program::'&lt;Main&gt;$'

It can be seen from thisThe essence of dynamic is indeed object, since it is an object, it can be confirmed that there is indeed a packing operation. This is actually in Microsoft's official documentationUsing type dynamicThere is an explanation above, the description is roughly like this

The dynamic type is a static type, but an object of type dynamic skips static type checking. Most of the time, the object is like having type object. At compile time, elements that are assumed to be dynamic support any operations. Therefore, it is not necessary to consider whether the object gets its own value from the COM API, from a dynamic language (such as IronPython), from an HTML document object model (DOM), from reflection, or from other locations in the program. However, if the code is invalid, an error is caught at runtime.

From here we can see that dynamic shows object, but dynamic will skip static type checking, so there will be no errors when compiling. If there are errors, an error will be reported at runtime, which means we are talking about determining the specific operation at runtime. This involves dynamic language runtime, a runtime environment that adds a set of dynamic language services to the common language runtime (CLR). Use DLR to easily develop dynamic languages ​​that run on .NET and add dynamic features to statically typed languages.

Anonymous Type

There will always be someone to take itdynamicandvarTo compare, but essentially, the two do not describe things at the same level.varIt is called an implicit type, which is essentially a syntactic sugar, which means that the specific type of the type can be determined during compilation, that is,Var essentially provides a simpler programming experience without affecting the behavior of the variable itself.This explains why the samevarDifferent types of values ​​cannot be assigned to variables multiple times. For example, the compiler will directly report an error when the following operations are performed.

var num = 123;
num = "123"; //Report an error

If you are using an integrated development environment, it is actually easy to find out. Put the mouse invarThe true type corresponding to the variable will be displayed on the type. Or it can be directly passedILSpyLook at the decompilation results, for example, declaredvar num = 123After compilation is completed

private static void <Main>$(string[] args)
{
	int num = 123;
	();
}

Please note that this is notobjectInstead, it is converted to a specific type because123It's the int type, take a closer lookILCode

.maxstack 1
.entrypoint
//Declared int32.locals init (
	[0] int32 num
)
// int num = 123;
IL_0000: ldc. 123
IL_0002: stloc.0

I believe you can see it heredynamicandvarIt's not a thing on the same level, indeed. var is an implicit type, syntax sugar, to simplify the programming experience, dynamic is a dynamic language runtime technology, which is converted to object type during compilation, because everything is an object on C#, and then the specific operations are performed during runtime.

Summarize

This article is mainly about seeing students discussing the thoughts about whether dynamic will be packed in the technical group. Relatively speaking, the explanation is relatively simple and basic. If you want to understand something more thoroughly, you must understand what it is step by step, so that you can better understand and think. It also confirms that you can't use it or because you don't understand it enough. When you have enough understanding of it, you will be able to operate it with ease.

This is the end of this article about the thoughts caused by C# dynamic packing. For more related C# dynamic packing content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!