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

12-17 18:49