Dela via


Pop Quiz!

Alright class.  Pop quiz time.  Say you have the following code:

 namespace What {
    class The {
        public static void Heck(uint[] array) {
            if (typeof(uint) != array.GetValue(0).GetType()) {
                throw new PleaseExplainThisToMeException();
            }
        }
    }
}

Under what circumstances could you expect the "PleaseExplainThisToMeException" thrown?

Note: You should be able to make the exception get thrown by just
making a regular call to this in C# without any use of things like
unsafe code or the like.

Comments

  • Anonymous
    July 02, 2005
    If the function were called from some other unspecified method which wasn't strict about the type checking, and passed a non-null array with at least 1 element, the first element being non-uint, the exception should be thrown.

    You should be able to generate such a method directly in IL (or using LCG in Whidbey), provided the call OpCode doesn't itself enforce type safety.

    Just a guess on my part. You see this sort of manual type-checking in dynamic languages frequently, as well as in HP48 System RPL.
  • Anonymous
    July 02, 2005
    Nope. You don't need IL. I'll update the post accordingly.
  • Anonymous
    July 02, 2005
    You can expect the exception to be thrown when the Martians attack.

    Or something like that.
  • Anonymous
    July 03, 2005
    int[] array = new int[1];
    array[0] = 1; What.The.Heck((uint[])(object)array);
  • Anonymous
    July 03, 2005
    See my blog on the subject... http://wesnerm.blogs.com/net_undocumented/2005/07/array_covarianc.html on Array Covariance for Enums.

    Arrays of enums are compatible with arrays of underlying integer type. Also, arrays of enums with the same underlying integer type are also compatible.

    Since the C# compiler disallows the direct conversion from arrays of enums to arrays of ints, an indirect conversion to the type Array or Object needs to first performed.

    uint[] array = (uint[]) (Array) new uintEnum[1];

    The CLR treats array of enums and array of integers virtually identically.
  • Anonymous
    July 03, 2005
    Interesting task! I've tried all solutions described above, but non of them worked as they suppose to be :) So here is my:

    namespace What
    {
    public enum Color: uint
    {
    Pink = 1,
    Red = 2
    }
    class The
    {
    public static void Heck(uint[] array)
    {
    if (typeof(uint) != array.GetValue(0).GetType())
    {
    throw new NotImplementedException();
    }
    }

    public static void Main()
    {
    Color[] colors = new Color[1];

    uint[] ints = new uint[1];
    ints = (uint[])colors.Clone();
    Heck(ints);
    }
    }
    }


    P.S. There is also problem with Array when creating non-zero based one dimensional array with Array.CreateInstace(...) method and then try to cast returned object to the one u want. It works for multidimensional, but not for single one.
  • Anonymous
    July 03, 2005
    Heck(null) throws the dreaded NullReferenceException.
  • Anonymous
    July 03, 2005
    Matt: Nope. It's not that difficult to get this to be thrown

    Rick: You got it! Congrats. I'll blog about this behavior later

    Stefan: You got it! Too bad you weren't as fast as Rick.

    Appwiz: That's not what i asked. I asked when the "PleaseExplainThisToMeException" would eb thrown. I originally wrote this to be more resilient to things like that, but i realized it didn't matter.
  • Anonymous
    July 03, 2005
    Um, Cyrus...

    Riks example is incorrect and yields a InvalidCastException. int[] can't be cast to uint[].

    The cast doesn't work on arrays of different integral types. It only works on arrays with the same integral type (either enums or the actual integer type)

    Stefan's example also is not minimal. Cloning the array is not required. All that is required is casting to (Array).

    if you have enum unitEnum : uint { None }, then my example works and you can look at my blog.

  • Anonymous
    July 03, 2005
    Wesner: my example does work, but I used 2.0b2. I just tried it with 1.1 and it throws an InvalidCastException, as you noted.

    Rik
  • Anonymous
    July 04, 2005
    Rick: I sow this "feature" in some of Whidbey betas too...
  • Anonymous
    July 04, 2005
    Cyrus,
    More than the solution, I am pretty curious as to how did you manage to come up with this problem?
  • Anonymous
    July 04, 2005
    not related to the solved quiz, but it kind of bugs me that:

    if (typeof(uint) != array.GetValue(0).GetType()) {}

    is not intuitively readable as:

    if (array.GetValue(0).GetType() != typeof(uint) {}

    ... or maybe it's just me.
  • Anonymous
    July 13, 2005
    The comment has been removed
  • Anonymous
    July 14, 2005
    What if you do something weird like marshall an array from a different version of the framework.

    e.x.: I'm running v1.1 of the framework and I pass in an array marshalled from v1.0.

    I'm guessing for two types to be equal, maybe they have to have the same assembly version#.