9

Do you feel question is strange? yes what happened also strange. let me explain.

I have found a snippet from this Covariance and Contravariance with C# Arrays

string[] strings = new string[1];
object[] objects = strings;
objects[0] = new object();

Jon skeet explains that above code will throw ArrayTypeMismatchException, as said yes it does.

what I did is I put a breakpoint in line 3, Using DebuggerVisualizer I manually set objects[0] = new object() it doesn't throw any error and it works. later checking strings[0].GetType() returns System.Object. not only System.Object any type can be set in string[] by above mentioned procedure.

I have no idea how this happened i raised my question as a comment over there in the very same question i saw this but no answers.

Am curious to know what is happening behind. Anybody explain pls.

Edit1 This is even Interesting

After reproducing the above behaviour try this

int len = strings[0].Length;

if you place mouse over the Property Length is says strings[0].Length threw ArgumentException with message Cannot find the method on the object instance but actually it doesnt throw exception and code runs yielding result len=0

Community
  • 1
  • 1
Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
  • 1
    +1. I just tested it with VS2008 and can confirm this behaviour. This *might* be a bug in the debugger, though. – Heinzi Jul 14 '13 at 16:42
  • @Heinzi I have tested it right now and it does not show this behaviour with VS 2008. Could you please test my code and confirm that you don't see the messagebox? – varocarbas Jul 14 '13 at 16:44
  • @varocarbas: I happens when you execute `objects[0] = new object();` *in the immediate window*, while execution is stopped at the breakpoint. Your code obviously throws as expected. – Heinzi Jul 14 '13 at 16:46
  • But if the execution is stopped, before the assignation occurs, logically there is no error. – varocarbas Jul 14 '13 at 16:49
  • 1
    @varocarbas: I've created a screenshot, maybe this will clear things up: http://tinypic.com/r/4kh10z/5. Note the stuff executed in the immediate window. – Heinzi Jul 14 '13 at 16:52
  • @Heinzi Interesting. Try some more stuff in the immediate window, like `strings.GetType()` (type of full array, not of 0-th element) and `object.ReferenceEquals(strings, objects)` – Jeppe Stig Nielsen Jul 14 '13 at 16:55
  • @Heinzi I got your idea, please, take a look at my updated answer and let me know what you think. – varocarbas Jul 14 '13 at 16:57
  • 1
    @Heinzi we cant say this is a bug in debugger. even if it is Runtime should not allow this. isn't it? – Sriram Sakthivel Jul 14 '13 at 16:57
  • @JeppeStigNielsen: `strings.GetType().ToString()` returns `System.String[]`, and `object.ReferenceEquals(strings, objects)` yields `true`. Yes, it's really as strange as it sounds. – Heinzi Jul 14 '13 at 16:57
  • 1
    @SriramSakthivel: Since the (faulty) assignment can (as far as we know) only be produced by using a debugger feature (the Immediate Window or the Autos/Locals/... Window), it might very well be that assignment in the debugger is less type-safe than assignment of compiled code. That's why I suspect a bug in the debugger, until we find a way to reproduce this behaviour without using a breakpoint and the VS debugging features. – Heinzi Jul 14 '13 at 17:00
  • 1
    This is so cool. So if you stop and debug, you can put any reference type into any other reference type variable. What happens if the program continues with `string s = strings[0]; Console.WriteLine(s.GetType());`? You could detach the debugger and let the program run again, with a non-string in `s`. – Jeppe Stig Nielsen Jul 14 '13 at 17:02
  • 1
    @JeppeStigNielsen: Not only reference types: Using your example I actually managed to store an int in a string. I've started a separate question about this: http://stackoverflow.com/q/17641734/87698 – Heinzi Jul 14 '13 at 17:21
  • @JeppeStigNielsen I have mentioned this in my question itself. `not only System.Object any type can be set in string[] by above mentioned procedure.` – Sriram Sakthivel Jul 14 '13 at 17:25
  • 1
    @Heinzi That must be a boxed `int` then. Remember that "silly" covariance of arrays does not apply to value types. For example `int[] ints = new int[1]; object[] objects = ints;` should not compile. – Jeppe Stig Nielsen Jul 14 '13 at 17:25
  • @JeppeStigNielsen I tried that too, doesnt helped, c#compiler kicked me off – Sriram Sakthivel Jul 14 '13 at 17:34

2 Answers2

1

Your example seems to answer the question: yes, a string reference can refer a non-string object. This is not intended, however.

Consider what you have found, a bug in the debugger.

As Jon Skeet explains in the answer you mention, because .NET arrays have this "crazy" covaraiance even though arrays are not read-only but more like read-write, everytime one writes to an array of references the framework has to check the type of the object one tries to write to the array, and throw an ArrayTypeMismatchException if you're about to use a wrong type, like assigning an instance of Cat to an array of Dogs (a runtime Dog[]) which has been cast by "crazy" covariance into an Animal[].

What you have demonstrated is that when we use the Immediate window of the Visual Studio debugger (or similar windows), this required type check is not done, and as a result this can lead to any type Y (except pointer types probably) being assigned to a reference type variable of any reference type X. Like this:

X[] arrayOfX = new X[1];
object[] arrayCastByCrazyCovariance = arrayOfX;
Y badObject = new Y();  // or another constructor or method to get a Y

// Set breakpoint here.
// In Immediate window assign:  arrayCastByCrazyCovariance[0] = badObject
// Detach debugger again.

X anomalousReferenceVariable = arrayOfX[0];

anomalousReferenceVariable.MemberOfX();  // or other bad things

This can make a Cat bark like a Dog, and stuff like that.

In the linked thread on Bypassing type safeguards, the answer by CodesInChaos shows an unrelated technique with which you can put a reference to an object of a "wrong" and unrelated type into a reference variable.

Community
  • 1
  • 1
Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
  • Just a correction in your statement. The debugger as I use it (that is, analysing variables after the code has passed through them; in the proposed example: stepping into this line and getting a popup message saying that an error was found) works as expected. What apparently does not work perfectly (or, at least, not exactly as in the normal execution of the code) is this feature of the Immediate Window which, I personally, haven't used ever before (and I do lots, but lots of debugging). I would love to get more insight into this but without coming to wrong conclusions: (out of space) – varocarbas Jul 15 '13 at 11:56
  • The debugger seen as on-time notification of actually executed code works perfectly. One of its features (which don't even need to be used and which might be understood as an estimation of what the code will do once it will be executed) has some bug or, at least, does not account for covariance situations (perhaps the complexity of the required implementation was too high and it was decided to not account for that and actually this limitation is known -> no idea). I hope that you will agree with this "small" clarification to your answer. – varocarbas Jul 15 '13 at 12:00
  • @varocarbas I can confirm that the "bug" involves only the feature where you change the value of an array entry manually. If you just step through code (well-compiled before before you started your application), this problem will not occur. – Jeppe Stig Nielsen Jul 15 '13 at 17:07
  • OK. Everything clear then. I am not an Immediate-Window user so no big deal for me :) – varocarbas Jul 15 '13 at 17:10
0

(I have preferred to rewrite my answer because the previous one had too many updates and wasn't clear enough).

Apparently, it has been found a not-so-perfect behaviour in one of the tools (Immediate Window) in the VS debugging part. This behaviour does not affect (AT ALL) the normal execution of the code and, purely speaking, does not affect even the debugging process.

What I meant in the last sentence above is that, when I debug code, I never use the Immediate Window, just write any code I want, execute it and see what the debugger shows. The referred problem does not affect this process (which can be called "debugging actually-executed code"; in the proposed example, pressing F11 when you are on objects[0] = new object();), what would imply a serious problem in VS. Thus from my point of view (the kind of debugging I do) and from the execution point of view, the referred error has no effect at all.

The only application of this error is when executing the "Immediate Window" functionality, a feature of the debugger which estimates what the code will deliver before it actually delivers it (what might be called "debugging not-executed code" or "estimating expected outputs from non-executed code", etc.; in the proposed example, being on line objects[0] = new object();, not pressing F11 but using the Immediate Window to input values and let this feature to tell you what is expected to happen).

In summary, the referred problem has to be understood within the right context, that is, it is not an overall-applicable problem, not even a problem in the whole debugger (when you press F11 in the referred line from the debugger, it outputs an error and thus the debugger does understand perfectly that this situation is wrong), but just in one of its tools. I am not even sure if this behaviour is even acceptable for this tool (i.e., what "Immediate Window" delivers is a prediction which might not be 100% right; if you want to know for sure what will happen, execute the code and let the debugger show you the information).

  • QUESTION: Can a String[] hold System.Object inside it?
  • ANSWER: NO.
  • CLARIFICATION: covariance is a complex reality which might not be perfectly accounted by some of the secondary tools in VS (e.g., "Immediate Window") and thus there might be cases where the aforementioned statement does not fully apply. BUT this is a local behaviour/bug in the specific tool with no effect in the actual execution of the code.
varocarbas
  • 12,354
  • 4
  • 26
  • 37
  • explained behaviour is seen in vs2010 as well as vs2012 – Sriram Sakthivel Jul 14 '13 at 16:56
  • Yeah, sure; everywhere. I didn't get your point properly; now I got it better; please, take a look at my updated answer and let me know what you think. – varocarbas Jul 14 '13 at 16:59
  • What do you mean `if (objects[0] == new object())`? One `new object()` is not equal to another `new object()`. The overload of `==` that takes in two `object` does a reference equality test. – Jeppe Stig Nielsen Jul 14 '13 at 17:05
  • Give me some minutes. – varocarbas Jul 14 '13 at 17:07
  • OK. the example I included was not the best one; I was just intending to support my point quickly and doing this kind of things quickly is not the best thing. My statement can be supported by itself: before happening an assignation, there is nothing wrong and thus no error is triggered and nothing has to be displayed by the debugger. If there is a step-in and the assignation actually occurs the error will appear and thus everything is as expected. – varocarbas Jul 14 '13 at 17:11