自从使用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.