【转】C#类型转换的开销
Explicit and implicit type casting is a common programming topic for almost any imperative programming language. Most C, C++, or Pascal programmers care about efficiency and speed of their code; but those who use managed programming environments, such as Java, Visual Basic, or C# rely all the optimizing tasks on the compiler and the runtime environment.
This can be a good approach in many cases, but managed languages are becoming more and more popular also for high-performance applications where the knowledge of the language, compiler, and runtime environment can enhance a program‘s quality and speed.
This article analyzes the most common type casting situations and the compiler behavior in them. We are going to study the MSIL generated code, but not the machine-specific instruction sequences due to the implementation and vendor dependency.
Casting primitive typesPrimitive types are those non-composed types which can be handled directly by the (virtual) machine instructions, i.e., int, long, float, etc... Those types doesn‘t have inner structure, and are always passed by value if the programmer doesn‘t specify explicitly other behavior (using the out and ref modifiers). Let‘s see a simple example about using and casting primitive types:
Hide Copy Code
int z = 10; double r = 3.4; uint n = 20; r = z; // Implicit conversion from int to double (1) z = (int)r; // Explicit conversion from double to int (2) n = (uint)z; // Explicit conversion from int to uint (3)This sample performs some conversions in the set of primitive types, leaving in some cases the casting tasks to the compiler and marking conversions explicitly in some other cases.
OK, time to dive into the MSIL generated code and check the impact of type casts in our code:
Hide Copy Code
.locals init ([0] int32 z, [1] float32 r, [2] unsigned int32 n) IL_0000: ldc.i4.s 10 IL_0002: stloc.0 IL_0003: ldc.r4 (9A 99 59 40) IL_0008: stloc.1 IL_0009: ldc.i4.s 20 IL_000b: stloc.2 //(1) IL_000c: ldloc.0 IL_000d: conv.r4 IL_000e: stloc.1 IL_000f: ldloc.1 //(2) IL_0010: conv.i4 IL_0011: stloc.0 IL_0012: ldloc.0 //(3) IL_0013: stloc.2 IL_0014: retAs we can see, there are several Conv.XY instructions in the code, whose function is to convert the value at the top of the stack to the type designed in the opcode (r4, i4, etc...). From now, we know that the "innocent" explicit and implicit conversions between primitive types generate instructions which can be avoided with a consistent type usage. The same conversions are applied in 64-bit data types, such as double, long and ulong.
Note that the last type cast doesn‘t need an explicit "Conv" opcode due to the nature of the involved types: intand uint; these types have a very close storage structure (big endian bit order with a sign bit in the signed type) and conversion sign issues must be controlled by the programmer.
A special kind of primitive type is bool (handled internally as an int), whose conversions to numeric types (and backward) are not allowed in C#, so we will not study them.
Downcasting object referencesC# provides two ways for casting object references (note that all types, unless those studied in the previous section, are reference types):
Hide Copy Code
object myClass = new MyClass(); ((MyClass)myClass).DoSome(); //(1) (myClass as MyClass).DoSome(); //(2)</CODE>The previous is a good example of downcasting (casting from the top to the bottom of the class hierarchy). The method used to perform the cast appears to be the same, but the generated MSIL sequences are a bit different:
Hide Copy Code
.locals init ([0] object myClass) IL_0000: newobj instance void Sample.MyClass::.ctor() IL_0005: stloc.0 IL_0006: ldloc.0 //(1) IL_0007: castclass Sample.MyClass IL_000c: callvirt instance void Sample.MyClass::DoSome() IL_0011: ldloc.0 //(2) IL_0012: isinst Sample.MyClass IL_0017: callvirt instance void Sample.MyClass::DoSome() IL_001c: ret温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/68705.html
- 上一篇:【温故知新】C#基于事件的异步模式(EAP)
- 下一篇:C#生成缩略图 (通用模式)