21

I'm debugging the following code:

class A 
{
    public virtual string X => "A";
}

class B : A
{
    public bool OwnX { get; set; } = true;
    public override string X
        => OwnX ? "B" : base.X; // (o)
}

class Program
{
    static void Main() => Console.WriteLine(new B().X);
}

And I have a breakpoint on the line marked with (o). When the breakpoint hit, I'm trying to evaluate base.X and getting its value "B":

strage base.X value?

The question is: why not "A"?

Filburt
  • 17,626
  • 12
  • 64
  • 115
ie.
  • 5,982
  • 1
  • 29
  • 44
  • 2
    Perhaps a UI bug because `base.X` is definitely going to be `A`. – DavidG Mar 16 '17 at 15:12
  • 1
    the debugger shows `"A"` for me, VS 2017. – Selman Genç Mar 16 '17 at 15:15
  • 1
    @SelmanGenç Shows `B` for me, also VS2017. – DavidG Mar 16 '17 at 15:16
  • @SelmanGenç hmm... strange, I just tried in both 2017 and 2015, both `"B"` – ie. Mar 16 '17 at 15:16
  • The debugger is showing `base.X = "B"` for me. – Abion47 Mar 16 '17 at 15:16
  • 2
    Okay, I think it might be a bug of the debugger. When I do `false ? "B" : base.X;`, hovering over `base.X` shows me `"B"`, but calling the property returns `"A"`. – Abion47 Mar 16 '17 at 15:19
  • @Abion47 here it is: http://imgur.com/a/EQbdm not sure if it matters but which VS edition u have installed? – Selman Genç Mar 16 '17 at 15:21
  • ...I just stopped and restarted the program, and now the debugger is showing `"A"` as well. – Abion47 Mar 16 '17 at 15:22
  • @SelmanGenç I'm running VS2017. – Abion47 Mar 16 '17 at 15:22
  • @SelmanGenç I'm in Community, looks like you're running a higher version as you have code lens? – DavidG Mar 16 '17 at 15:23
  • @DavidG yes I got professional edition – Selman Genç Mar 16 '17 at 15:25
  • The debugger is definitely getting it wrong. If you set `OwnX` to false, it shows the correct value. – DavidG Mar 16 '17 at 15:26
  • Yeah, I've discovered the problem. When I specify `true`, it shows the value for class `B`. When I specify `false`, it shows the value for class `A`. See: http://i.imgur.com/od4CZMA.png – Abion47 Mar 16 '17 at 15:28
  • I reproduced the issue after setting `OwnX` to true, didn't realize I have changed it to false. now `base.X` shows `B` in the debugger – Selman Genç Mar 16 '17 at 15:52
  • 5
    @ie., The CLR doesn’t support func eval of a base class method. The old Expression Evaluator used to give an error message in this case. There’s already a github issue for this issue here: https://github.com/dotnet/roslyn/issues/3723. – Jack Zhai Mar 22 '17 at 02:36
  • 1
    @JackZhai-MSFT Sorry if I'm misunderstanding, but I thought that the CLR did support that -- that the `call` instruction was allowed to call a function non-virtually for any class, that it merely rendered the IL unverifiable? I don't see any significant restrictions in the spec (ECMA-335) in the "Correctness" section, at any rate: it merely reads "Correct CIL ensures that the stack contains a `this` pointer if required and the correct number and type of arguments for the method being called" followed by something not relevant here. Is it in a specific context that it's disallowed, then? –  Mar 22 '17 at 18:49
  • Follow up: This issue has been moved to the Roslyn Github repo: https://github.com/dotnet/roslyn/issues/28166 – DavidG Jun 28 '18 at 16:41
  • @user743382: Jack's comment is unclear. The runtime that actually runs your program of course supports that feature. The **expression evaluator that the debugger calls into** does not support that feature. – Eric Lippert Nov 07 '18 at 19:57

3 Answers3

1

This is a Roslyn bug

As others have mentioned, this bug is well known.

You can trivially check that the actual value of base.X is A, it is just the Expression Evaluator that returns the wrong result:

This one is in Rider

Marcell Toth
  • 3,433
  • 1
  • 21
  • 36
  • 1
    What was the point of posting this? We know it's a bug, that's already been extensively mentioned in the comments. This doesn't add anything useful. – DavidG Nov 07 '18 at 23:17
-1

Because X is not evaluated in runtime, it will also not evaluate in the debugger. So it assumes it is the same.

Because base.X is not actually called, it has never been evaluated as A. The overwriting property is because of that leading.

If you'd like to do so, make a constant out of it.

-6

Maybe you should read a little bit more about this ?: Operator https://learn.microsoft.com/en-us/dotnet/articles/csharp/language-reference/operators/conditional-operator

Since default value OwnX is true.

Give it a try to this code:

 B b = new B();
 b.OwnX = false;
 Console.WriteLine(b.X);

Explaining this code: public override string X => OwnX ? "B" : base.X;

to make it more readable:

public override string X
{
   get {
      if (Ownx == true) // this is the default value.
      {
          return "B";
      }
      else{
          return "A";
      }
}
Roberto12cr
  • 15
  • 1
  • 10
  • You have completely missed the point of the question. The functionality isn't in dispute, it's the fact that the debugger is showing the *incorrect* value. – DavidG May 10 '17 at 14:47
  • Maybe the confusion is related to the override of X. Since B contains an override for this property when you use base.X it will return the value of B. The pointer of the class instance will not point to the definition on A, because this is a virtual method. From B class there is no way to the the value of the virtual method. Hope this help – Roberto12cr May 10 '17 at 19:29
  • The point is that nobody (apart from the devs) can know the answer. – DavidG May 10 '17 at 20:00
  • As I suspected, this is a Roslyn bug so this answer is absolutely not correct. – DavidG Jun 28 '18 at 16:40