自從使用C#以來,很少用到內聯函數,甚至都沒想過,但從事數據采集處理過程中追求處理速度與代碼簡潔時,內聯無疑是一個利器。
不同於C++的 inline 關鍵字,在C#中需要使用特性,使用方法如下:
MethodImpl:實現了Method, Impl,implemented,其指示 CLR 即時編譯時的方式。
MethodImplOptions:是一個枚舉類型,但允許按位組合。
其中 AggressiveInlining 表示,The method should be inlined if possible.(即不保證一定會內聯)
class TestClass {
//運行時才能決定是否執行內聯 [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public ushort setUInt16(float src, ushort k = 1) { return (ushort)(src * k); } //對照 public uint setUInt32(float src, uint k = 10) { return (uint)(src * k); } } class Program { static DateTime StartTime = DateTime.Now; static void Main(string[] args) { TestClass my = new TestClass(); ushort ms = my.setUInt16(10, 2); uint mi = my.setUInt32(10.2f, 2); } }
C#在開發時編譯結果是中間語言,通過 ILDASM 查看,主要代碼如下:
.method public hidebysig instance uint16 setUInt16(float32 src, [opt] uint16 k) cil managed aggressiveinlining { .param [2] = uint16(0x0001) // 代碼大小 6 (0x6) .maxstack 8 IL_0000: ldarg.1 IL_0001: ldarg.2 IL_0002: conv.r4 IL_0003: mul IL_0004: conv.u2 IL_0005: ret } // end of method TestClass::setUInt16 .method public hidebysig instance uint32 setUInt32(float32 src, [opt] uint32 k) cil managed { .param [2] = uint32(0x0000000A) // 代碼大小 7 (0x7) .maxstack 8 IL_0000: ldarg.1 IL_0001: ldarg.2 IL_0002: conv.r.un IL_0003: conv.r4 IL_0004: mul IL_0005: conv.u4 IL_0006: ret } // end of method TestClass::setUInt32 .method private hidebysig static void Main(string[] args) cil managed { .entrypoint // 代碼大小 31 (0x1f) .maxstack 8 IL_0000: newobj instance void S7SmartDriver.TestClass::.ctor() IL_0005: dup IL_0006: ldc.r4 10. IL_000b: ldc.i4.2 IL_000c: callvirt instance uint16 S7SmartDriver.TestClass::setUInt16(float32, uint16) IL_0011: pop IL_0012: ldc.r4 10.2 IL_0017: ldc.i4.2 IL_0018: callvirt instance uint32 S7SmartDriver.TestClass::setUInt32(float32, uint32) IL_001d: pop IL_001e: ret } // end of method Program::Main
在 setInt16 上加的 MethodImplOptions.AggressiveInlining 特性,對應於 IL 中的 aggressiveinlining, 而兩者在 Main 調用方式沒有區別。
在運行時CLR會將 IL 代碼即時編譯, 此時會根據CPU型號進行優化,至於在運行時是否真的進行了內聯,那就看CLR的心情啦。
畢竟 aggressiveinlining 並非C++中的內聯,也非宏替換,只是 The method should be inlined if possible.