What is the difference between Expression bodied s

2019-07-23 12:48发布

问题:

I would like to understand the IL code a bit.

So as you see the expression bodied has less code than the GetOld code. Is it some optimization done there and means expression body syntax is more performant?

Or it does not really matter?

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; }
        }
    }
}

And the generated IL Code using DotPeek

https://gist.github.com/anonymous/9673389a1a21d0ad8122ec97178cfd9a

回答1:

There is none. That code compiles to the exact same C# using Roslyn, so the IL is no different:

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;
            }
        }
    }
}


回答2:

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

The added instructions are:

  1. A nop instruction, whose purpose is to do nothing.
  2. A br instruction, which jumps to the following instruction; in effect, this does nothing.
  3. A stloc-ldloc pair of instructions, which store and then load the value from a local variable, which in effect does nothing.

So, the added instructions don't do anything. I believe most of them are there to aid in debugging (i.e. the nop is there so that you can place a breakpoint on the opening brace; this is represented by a comment in your dotPeek output). Some of them might be artifacts of how the compiler works internally and are not removed in Debug mode, because there is no reason to do that.

In the end, the difference doesn't matter. And it can't cause performance difference in Release mode, since there is no difference in IL in that mode.



标签: c# cil