9

A piece of C# code

var isTrue = (new List<int>{1,2,3} is IEnumerable<object>);

I got result false in code execution, but when I copy that code into WATCH window, the result is true.

Evk
  • 98,527
  • 8
  • 141
  • 191
Raymond He
  • 127
  • 5
  • 1
    I assume `IEnumable` is a typo? – casiosmu Nov 30 '17 at 07:35
  • Possible duplicate of [Difference between Covariance & Contra-variance](https://stackoverflow.com/questions/2184551/difference-between-covariance-contra-variance) – Manfred Radlwimmer Nov 30 '17 at 07:36
  • TL;DR: a `List` is a `IEnumerable` but not a `IEnumerable`. `false` is the correct result. – Manfred Radlwimmer Nov 30 '17 at 07:37
  • 1
    @ManfredRadlwimmer that's of course the correct answer for the code execution behaviour. The interesting part of this question is: why does the debugger watch window disagree? I can reproduce this. – René Vogt Nov 30 '17 at 07:40
  • @RenéVogt Well, I'll be damned - same happens in the Immediate Window. – Manfred Radlwimmer Nov 30 '17 at 07:43
  • This is obviously a bug in the debugger. The reason could be some (another) unfortunate situation where the CLR and C# don't actually enforce the same rules, but this claim seems flaky at best, and I don't have time right now to check the exact CLR variance rules and if thety match up 100% with C#'s. Whats obvious is that, as far as C# is concerned at least, type variance is not allowed when it involves generic types that are value types, so the debugger is simply wrong. – InBetween Nov 30 '17 at 07:53
  • Small update: even `new List{1,2,3} as IEnumerable` works o_O – Manfred Radlwimmer Nov 30 '17 at 07:53
  • More updates; issue can't be reproduced with arrays: `new int[] {1, 2, 3} is IEnumerable` returns the correct result (`false`) in the immediate window. – InBetween Nov 30 '17 at 08:00
  • Thanks for all of ur answers, I don't know why u cannot reproduce this case. as u know you can get this result during ur execution with the result is false. But if you copy this piece of code into immediate window, you will get a true result. So this's my doubt, is there any issues about VS. Mark: I m using VS2015 – Raymond He Nov 30 '17 at 09:13
  • @RaymondHe we actually _can_ reproduce this (in VS2017 too). – Evk Nov 30 '17 at 09:28
  • I think this is related to https://developercommunity.visualstudio.com/content/problem/142642/inconsistent-result-of-covariance-for-primitive-an.html and it seems they have it under investigation. – Dzyann Dec 15 '17 at 13:26

1 Answers1

1

This is not a complete answer (I don't know the reasons why this bug is cropping up), but it sheds some light on the erratic behaviour of the debugger which is obviously buggy.

First and foremost: C# disallows (and AFAIK, the CLR too) type variance involvig value types; variance is only allowed if there is an identity preserving conversion between the involved types, otherwise it will fail (there is no identity preserving conversion for value types):

object[] oo = new int[] {1, 2, 3}; //will fail
IEnumerable<object> oo = new int[] {1, 2, 3}; //will fail

The debugger's immediate window is obviously wrong, new List<int> { 1, 2, 3 } is IEnumerable<object> should return false as the runtime does. Why is it returning true? Because there's a bug, period.

What makes it even more bewildering is the fact that new int[] { 1, 2, 3 } is IEnumerable<object> will correclty return false when int[] is implicitly convertible to IEnumerable<int> same as List<int>.

The only reason I find for the latter correct behavior is that the compiler already flags that expression as always false with a warning and therefore the way the compiler analyzes the array scenario is different from any other IEnumerable.

InBetween
  • 32,319
  • 3
  • 50
  • 90