7

I was trying around a bit with Try Roslyn when I entered this piece of code:

using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.CSharp;

public class C {

    public C()
    {
        x = 4;
    }

    public int x { get; } = 5;
}

And it gave me back this code:

using System;
using System.Diagnostics;
using System.Reflection;
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]
public class C
{
    [DebuggerBrowsable(DebuggerBrowsableState.Never), CompilerGenerated]
    private readonly int <x>k__BackingField;
    public int x
    {
        [CompilerGenerated]
        get
        {
            return this.<x>k__BackingField;
        }
    }
    public C()
    {
        this.<x>k__BackingField = 5;
        base(); // This is not valid C#, but it represents the IL correctly.

        this.<x>k__BackingField = 4;
    }
}

What I don't get is why it would do the assignment of the backing field twice inside of the constructor:

        this.<x>k__BackingField = 5;
        base(); // This is not valid C#, but it represents the IL correctly.

        this.<x>k__BackingField = 4;. 

Is this an error of the website or does the Roslyn compiler actually do this (would be really dumb imo)?


What I mean is that if I do

 public C(int x)
 {
   this.x = x;
 }

public int x { get; } = 5;

And have that code created:

public C(int x)
{
    this.<x>k__BackingField = 5;
    base(); // This is not valid C#, but it represents the IL correctly.

    this.<x>k__BackingField = x;
}

But shouldn't it optimize that out?

Mafii
  • 7,227
  • 1
  • 35
  • 55
  • 2
    `Is this an error of the website or does the Roslyn compiler actually do this (would be really dumb imo)?` Setting a default then overriding it in the constructor isn't exactly usual (to put it politely) – Rhumborl May 25 '16 at 12:10
  • @Rhumborl it is if you have multiple constructors and some have a value as parameter and some dont. see edit – Mafii May 25 '16 at 12:11
  • 1
    @Mafii I deleted my answer - it was wrong! (I forgot to click a button in Reflector...) – Matthew Watson May 25 '16 at 12:22
  • @MatthewWatson oh, thank you for letting me know, I was confused! – Mafii May 25 '16 at 12:23

2 Answers2

11

Because you set it twice in your code:

public C()
{
    //here
    x = 4;
}

//and here
public int x { get; } = 5;

Update after edit of question

But shouldn't it optimize that out?

It probably could, but only if that class doesn't inherit from another class that uses that value in its constructor, it knows that it's an auto-property and the setter doesn't do anything else.

That would be a lot of (dangerous) assumptions. The compiler needs to check a lot of things before making an optimization like that.

Manfred Radlwimmer
  • 13,257
  • 13
  • 53
  • 62
  • The compiler knows that the class doesn't derive from another class (other than `object`) and the optimisation is not performed even if the class is sealed. So your explanation doesn't cover those cases... The assumptions you mention aren't assumptions at all - the compiler KNOWS whether they are the case. – Matthew Watson May 25 '16 at 12:29
  • @MatthewWatson I absolutely agree, I just wanted to point out that it's "not that easy". `The compiler needs to check a lot of things before making an optimization like that.` doesn't mean it doesn't or can't. – Manfred Radlwimmer May 25 '16 at 12:37
4

The reason is that you are setting it twice in your code, both in the property declaration and in the constructor.

The C# 6.0 readonly property

public int x { get; }

Works just like a readonly field regarding value assignment: you can set it in either the constructor or at the place of the declaration.

EDIT

  • There are two parts of this issue: First, the current http://tryroslyn.azurewebsites.net/ (as of 2016.05.25) compile the code in DEBUG mode, even if the Release option is chosen at the header of the page.
  • Second the Roslyn really does not optimize out the double declaration of the readonly property, so if you use VS15 and compile this code in release mode, the x will be assigned twice as well

An example for the usage of initializing the readonly property for multiple time can be the usage of multiple constructors, where only one redefines the "default" value you set for the property.

However in your case, optimization would not be a bad idea, it might be worthwhile to raise this as a feature request on the Roslyn github page

Márk Gergely Dolinka
  • 1,430
  • 2
  • 11
  • 22
  • I'm totally aware of that. I wanted to know why it isn't optimized out. Onclear question, my fault, check edit. – Mafii May 25 '16 at 12:13
  • 1
    Thanks for the clarification, this issue is not on Roslyn but the website itself is unfinished ;) – Márk Gergely Dolinka May 25 '16 at 12:17
  • I think in this situation its actually overkill (what does it cost to set an int) but it might be useful if there are more complex or expensive datatypes. I'll look into it. – Mafii May 26 '16 at 07:49
  • You are right, performance wise a simple int assignment is negligible, but as you said if there are complex data types, which might include database or network operations (e.g. REST api calls) it might be problematic. – Márk Gergely Dolinka May 26 '16 at 07:56
  • 1
    Another thing: while optimizing this out might be an overkill, but the intellisense could show a hint/warning, that the first assignment will be overwritten. Well that would be cool :) – Márk Gergely Dolinka May 26 '16 at 07:57