Thread: really annoying limitation of array cast

  1. #1
    3735928559
    Join Date
    Mar 2008
    Location
    RTP
    Posts
    838

    really annoying limitation of array cast

    Code:
    namespace ConsoleApplication1
    {
        class ImplicitlyConvertibleFromFoo
        {
            public ImplicitlyConvertibleFromFoo(Foo foo)
            {
                this.foo = foo;
            }
            Foo foo;
        }
        class Foo
        {
            public static implicit operator ImplicitlyConvertibleFromFoo(Foo foo)
            {
                return new ImplicitlyConvertibleFromFoo(foo);
            }
        }
        class Program
        {
            static void Main(string[] args)
            {
                Foo[] fooArray = new Foo[4];
                for(int i=0;i<fooArray.Length;++i)
                {
                    fooArray[i] = new Foo();
                }
                ImplicitlyConvertibleFromFoo implicitlyConverted = fooArray[0];
                // this is fine
    
                ImplicitlyConvertibleFromFoo[] castArray = fooArray.Cast<ImplicitlyConvertibleFromFoo>().ToArray();
    // above generates exception: An unhandled exception of type 'System.InvalidCastException' occurred in System.Core.dll
    
    //Additional information: Unable to cast object of type 'ConsoleApplication1.Foo' to type 'ConsoleApplication1.ImplicitlyConvertibleFromFoo'.
            }
        }
    }
    does anyone know a way to easily convert arrays of user-defined types?

  2. #2
    3735928559
    Join Date
    Mar 2008
    Location
    RTP
    Posts
    838
    this works, but how asinine to have to use LINQ and a lambda to do something that seemingly should be handled by the method above. dotfail.

    Code:
    ImplicitlyConvertibleFromFoo[] castArray = fooArray.Select(item => (ImplicitlyConvertibleFromFoo)item).ToArray();

  3. #3
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    Did you try adding an explicit cast to cast Foo as well? I'm pretty sure the IEnumerable.Cast<T>() method is basically this:
    Code:
    public static IEnumerable<T> Cast<T>(this IEnumerable items)
    {
      foreach(object item in items)
        yield return (T)item;
    }
    The code above is untested, but you get the idea.
    If you understand what you're doing, you're not learning anything.

  4. #4
    3735928559
    Join Date
    Mar 2008
    Location
    RTP
    Posts
    838
    Duplicate user-defined conversion in type 'ConsoleApplication1.Foo'


    changing implicit to explicit (which doesn't make any sense why that should help) yields the same exception.
    Last edited by m37h0d; 03-14-2012 at 01:06 PM.

  5. #5
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    If you understand what you're doing, you're not learning anything.

  6. #6
    3735928559
    Join Date
    Mar 2008
    Location
    RTP
    Posts
    838
    yes, clearly it doesn't. seems rather asinine to me.

  7. #7
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    Before jumping down .NET's throat, I would recommend you present your question to Eric Lippert, one of the C# compiler designers for Microsoft. He seems extremely approachable and might be able to answer the question fully: Contact - Fabulous Adventures In Coding - Site Home - MSDN Blogs
    If you understand what you're doing, you're not learning anything.

  8. #8
    Registered User
    Join Date
    Sep 2011
    Posts
    71
    To expand on itsme86's post, notice that the Cast<T>() extension method, unlike most extension methods defined in System.Linq.Enumerable, extends non-generic IEnumerable, not generic IEnumerable.

    That said, how else could the the Cast<T>() extension method treat the elements of the non-generic IEnumerable than as System.Objects?

    The conversion from the type of the elements of the non-generic IEnumerable to System.Object is straightforward. It's just an implicit boxing conversion.

    So the problem is when you try to convert - implicitly or explicitly - from an instance of System.Object to an instance of a type other than the underlying type of the System.Object. You can get away with this if the type you are trying to convert to is a base type of the underlying type of the System.Object, but it doesn't work with other kinds of conversions.

    In other words, the code fails because you are essentially trying to do this:

    Code:
    int x = 10;
    object o = x; //boxing
    long y = (long)o; //InvalidCastException - long is not a base type of int
    Which is different from doing this:

    Code:
            class A { }
            class B : A { }
            static void Main(string[] args)
            {
                B b = new B();
                object o = b;
                A a = (A)o; // no problem
           }
    Until a Cast extension method that takes in 2 type parameters is introduced to the .NET framework, you can define your own Cast<T,U> extension method:

    Code:
    namespace ConsoleApplication1
    {
        class ImplicitlyConvertibleFromFoo
        {
            public ImplicitlyConvertibleFromFoo(Foo foo)
            {
                this.foo = foo;
            }
            Foo foo;
        }
        class Foo
        {
            public static implicit operator ImplicitlyConvertibleFromFoo(Foo foo)
            {
                return new ImplicitlyConvertibleFromFoo(foo);
            }
        }
        static class F
        {
            public static IEnumerable<T> Cast<T,U>(this IEnumerable<U> items) where T : class
            {
                foreach (U item in items)
                    yield return item as T;
            }
    
        }
        class Program
        {
            static void Main(string[] args)
            {
         
                Foo[] fooArray = new Foo[4];
                for (int i = 0; i < fooArray.Length; ++i)
                {
                    fooArray[i] = new Foo();
                }
                ImplicitlyConvertibleFromFoo implicitlyConverted = fooArray[0];
                // this is fine
    
                ImplicitlyConvertibleFromFoo[] castArray = fooArray.Cast<ImplicitlyConvertibleFromFoo, Foo>().ToArray();
            }
        }
    }
    Notice that (T)item doesn't work since the compiler has no way to tell if a conversion operator exists for type parameters T and U. The "as" operator works, but since it returns null if the conversion cannot be performed we need to add a generic constraint specifying that T must be a reference type.
    Last edited by y99q; 03-14-2012 at 10:37 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Annoying Array - Simple Problem ( I hope)
    By Parrot in forum C Programming
    Replies: 4
    Last Post: 11-05-2011, 08:35 PM
  2. cast to a reference to a static array
    By m37h0d in forum C++ Programming
    Replies: 2
    Last Post: 05-30-2009, 02:40 AM
  3. limitation
    By aama100 in forum C++ Programming
    Replies: 10
    Last Post: 02-04-2008, 10:22 PM
  4. SMS limitation ?
    By khpuce in forum A Brief History of Cprogramming.com
    Replies: 9
    Last Post: 01-12-2005, 05:12 PM