表达式主体语法与 IL 级别的 Getter 语法有什么区别?
What is the difference between Expression bodied syntax vs Getter syntax on IL level?
我想稍微了解一下IL代码。
因此,如您所见,表达式 bodied 的代码少于 GetOld 代码。是否在那里进行了一些优化,意味着表达式主体语法的性能更高?
或者这并不重要?
namespace DatabaseModules {
public class Test {
public IList<string> _cache = new List<string>();
public Test() {
}
public IList<string> Get => _cache;
public IList<string> GetOld {
get { return _cache; }
}
}
}
以及使用 DotPeek 生成的 IL 代码
https://gist.github.com/anonymous/9673389a1a21d0ad8122ec97178cfd9a
有none。该代码 compiles to the exact same C# 使用 Roslyn,因此 IL 没有什么不同:
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
[assembly: AssemblyVersion("0.0.0.0")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[module: UnverifiableCode]
namespace DatabaseModules
{
public class Test
{
public IList<string> _cache = new List<string>();
public IList<string> Get
{
get
{
return this._cache;
}
}
public IList<string> GetOld
{
get
{
return this._cache;
}
}
}
}
When compiling in Release mode, both properties produce the same IL:
.method public hidebysig specialname
instance class [mscorlib]System.Collections.Generic.IList`1<string> get_Get () cil managed
{
// Method begins at RVA 0x2063
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.Collections.Generic.IList`1<string> DatabaseModules.Test::_cache
IL_0006: ret
} // end of method Test::get_Get
.method public hidebysig specialname
instance class [mscorlib]System.Collections.Generic.IList`1<string> get_GetOld () cil managed
{
// Method begins at RVA 0x2063
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.Collections.Generic.IList`1<string> DatabaseModules.Test::_cache
IL_0006: ret
} // end of method Test::get_GetOld
When compiling in Debug mode, the IL is indeed different:
.method public hidebysig specialname
instance class [mscorlib]System.Collections.Generic.IList`1<string> get_Get () cil managed
{
// Method begins at RVA 0x2065
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.Collections.Generic.IList`1<string> DatabaseModules.Test::_cache
IL_0006: ret
} // end of method Test::get_Get
.method public hidebysig specialname
instance class [mscorlib]System.Collections.Generic.IList`1<string> get_GetOld () cil managed
{
// Method begins at RVA 0x2070
// Code size 12 (0xc)
.maxstack 1
.locals init (
[0] class [mscorlib]System.Collections.Generic.IList`1<string>
)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldfld class [mscorlib]System.Collections.Generic.IList`1<string> DatabaseModules.Test::_cache
IL_0007: stloc.0
IL_0008: br.s IL_000a
IL_000a: ldloc.0
IL_000b: ret
} // end of method Test::get_GetOld
添加的说明是:
- 一条
nop
指令,其目的是什么都不做。
- 一条
br
指令,跳转到后面的指令;实际上,这什么都不做。
- 一对
stloc
-ldloc
指令,存储然后从局部变量加载值,实际上什么都不做。
所以,添加的指令没有做任何事情。我相信它们中的大多数都是为了帮助调试(即 nop
在那里,以便您可以在左大括号上放置一个断点;这由 dotPeek 输出中的注释表示)。其中一些可能是编译器内部工作方式的产物,在调试模式下不会被删除,因为没有理由这样做。
说到底,差异并不重要。并且它不会导致 Release 模式下的性能差异,因为在该模式下 IL 没有差异。
我想稍微了解一下IL代码。
因此,如您所见,表达式 bodied 的代码少于 GetOld 代码。是否在那里进行了一些优化,意味着表达式主体语法的性能更高?
或者这并不重要?
namespace DatabaseModules {
public class Test {
public IList<string> _cache = new List<string>();
public Test() {
}
public IList<string> Get => _cache;
public IList<string> GetOld {
get { return _cache; }
}
}
}
以及使用 DotPeek 生成的 IL 代码
https://gist.github.com/anonymous/9673389a1a21d0ad8122ec97178cfd9a
有none。该代码 compiles to the exact same C# 使用 Roslyn,因此 IL 没有什么不同:
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
[assembly: AssemblyVersion("0.0.0.0")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[module: UnverifiableCode]
namespace DatabaseModules
{
public class Test
{
public IList<string> _cache = new List<string>();
public IList<string> Get
{
get
{
return this._cache;
}
}
public IList<string> GetOld
{
get
{
return this._cache;
}
}
}
}
When compiling in Release mode, both properties produce the same IL:
.method public hidebysig specialname
instance class [mscorlib]System.Collections.Generic.IList`1<string> get_Get () cil managed
{
// Method begins at RVA 0x2063
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.Collections.Generic.IList`1<string> DatabaseModules.Test::_cache
IL_0006: ret
} // end of method Test::get_Get
.method public hidebysig specialname
instance class [mscorlib]System.Collections.Generic.IList`1<string> get_GetOld () cil managed
{
// Method begins at RVA 0x2063
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.Collections.Generic.IList`1<string> DatabaseModules.Test::_cache
IL_0006: ret
} // end of method Test::get_GetOld
When compiling in Debug mode, the IL is indeed different:
.method public hidebysig specialname
instance class [mscorlib]System.Collections.Generic.IList`1<string> get_Get () cil managed
{
// Method begins at RVA 0x2065
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.Collections.Generic.IList`1<string> DatabaseModules.Test::_cache
IL_0006: ret
} // end of method Test::get_Get
.method public hidebysig specialname
instance class [mscorlib]System.Collections.Generic.IList`1<string> get_GetOld () cil managed
{
// Method begins at RVA 0x2070
// Code size 12 (0xc)
.maxstack 1
.locals init (
[0] class [mscorlib]System.Collections.Generic.IList`1<string>
)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldfld class [mscorlib]System.Collections.Generic.IList`1<string> DatabaseModules.Test::_cache
IL_0007: stloc.0
IL_0008: br.s IL_000a
IL_000a: ldloc.0
IL_000b: ret
} // end of method Test::get_GetOld
添加的说明是:
- 一条
nop
指令,其目的是什么都不做。 - 一条
br
指令,跳转到后面的指令;实际上,这什么都不做。 - 一对
stloc
-ldloc
指令,存储然后从局部变量加载值,实际上什么都不做。
所以,添加的指令没有做任何事情。我相信它们中的大多数都是为了帮助调试(即 nop
在那里,以便您可以在左大括号上放置一个断点;这由 dotPeek 输出中的注释表示)。其中一些可能是编译器内部工作方式的产物,在调试模式下不会被删除,因为没有理由这样做。
说到底,差异并不重要。并且它不会导致 Release 模式下的性能差异,因为在该模式下 IL 没有差异。