2

I would not have thought that its possible, but it seems you somehow can create and fill an C# array of a "wrong" type.

I stumbled upon the following anomaly in Unity 4.2.1 today:

Editor[] editors = ActiveEditorTracker.sharedTracker.activeEditors;
Debug.Log(editors.GetType().Name);
Debug.Log(editors.GetType().GetElementType().Name);
Debug.Log(typeof(Editor).IsAssignableFrom(editors[0].GetType()));
Debug.Log(typeof(Editor).IsAssignableFrom(editors.GetType().GetElementType()));

It prints the following output:

MonoBehaviour[]
MonoBehaviour
True
False

In Unity, the class "MonoBehaviour" and "Editor" are unrelated slibbings (both inherit from UnityEngine.Object, but neither from the other). They are not assignable to each other or related in any way I can see that would make the above output possible.

So my question is: The Heck?

More detailed question: How is it possible to create an array of the "wrong" type and fill it with elements of the "right" type? I want to do this too! How do I circumvent the array checks from C#? (maybe using unsafe()?)

My current gut-feeling is, that C# only prevent writing to the wrong array (via ArrayTypeMismatchException), but if you somehow magically fill the array (in case of Unity, probably using dark C++ magic), it just works..?

(Funny also: If I do this editors[0] = editors[0] I get the mentioned ArrayTypeMismatchException)

Edit: Also funny: Array self = editors; editors = (Editor[])self; throws an InvalidCastException

Imi
  • 1,579
  • 1
  • 12
  • 22
  • When `editors[0]` has a type that _is_ assignable "to" `Editor` (your "True" output), why would the assignment `editors[0] = editors[0]` throw `ArrayTypeMismatchException`? – Jeppe Stig Nielsen Sep 20 '13 at 10:36
  • Will the code `Array self = editors; editors = (Editor[])self;` aslo fail with a runtime exception? – Jeppe Stig Nielsen Sep 20 '13 at 10:39
  • You: _I want to do this too!_ One way of doing it is in [this answer](http://stackoverflow.com/a/17643662/1336654). You simply need to change the type of the field in `Evil` from `string` (which that example uses) to `Editor[]`. After that you can put ***any*** object into an `Editor[]` reference. Nasty. – Jeppe Stig Nielsen Sep 20 '13 at 10:45
  • 1
    _When editors[0] has a type that is assignable "to" Editor (your "True" output), why would the assignment editors[0] = editors[0] throw ArrayTypeMismatchException_ Because the runtime type of the array itself is not Editor[] but MonoBehaviour[] (and its ElementType is MonoBehaviour). Yea.. I know something is fishy here, but I have it before my very eyes.. The static type of my variable "editors" does not match the runtime type. :-O – Imi Sep 20 '13 at 11:06
  • _Will the code Array self = editors; editors = (Editor[])self; aslo fail with a runtime exception?_ Yes, it throws an `InvalidCastException`. Which is comforting to me - at least something I excpected :-D – Imi Sep 20 '13 at 11:07
  • _One way of doing it is in this answer._ Mh.. yea.. interesting. Interestingly, the type Editor is marked with `[StructLayout(LayoutKind.Sequential)]` when using a disassembler, although its a class type. And when trying to get the attribute via runtime reflection, its not there anymore.. :-O – Imi Sep 20 '13 at 11:08

1 Answers1

0

Some magic

Editor[] editors =  ActiveEditorTracker.sharedTracker.activeEditors;

    Editor e0 = editors[0];
    Editor e1 = editors[1];
    Editor e2 = editors[2];

    Editor[] test = {e0, e1, e2};

    Debug.Log(test.GetType());

    Debug.Log(typeof(Editor).IsAssignableFrom(test[0].GetType()));
    Debug.Log(typeof(Editor).IsAssignableFrom(test.GetType().GetElementType()));

UnityEditor.Editor[] UnityEngine.Debug:Log(Object)

True UnityEngine.Debug:Log(Object)

True UnityEngine.Debug:Log(Object)

Valery Petrov
  • 653
  • 7
  • 19