Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic explicit cast failure C#

I've some issues with the following piece of code. I would like to explicit a string to an object, this is working perfectly fine, however, if this object is part of a generic class, this is failing with the following error exception: "Unable to cast object of type 'System.String' to type 'test.B'". Even though I've overloaded the the method.

using System;
using System.Collections.Generic;

namespace test {
    class Program {
        static void Main(string [] args) {
            // These two cast perfectly fine.
            B x = (B) "abc";
            C y = (C) "def";

            A <B> a = new A<B>();
            a.b();
            A <C> b = new A<C>();
            b.b();
        }
    }

    class A<T> {
        public List <T> a = new List<T>();

        public void b() {
            // Unable to cast object of type 'System.String' to type 'test.B'
            this.a.Add ((T) (object) "abc"); 
            this.a.Add ((T) (object) "def");
            this.a.Add ((T) (object) "ghi");
        }
    }

    class B {
        public string b;

        public static explicit operator B(string a) {
            B x = new B();
            x.b = a;
            return x;
        }
    }

    class C {
        public string c;

        public static explicit operator C(string a) {
            C x = new C();
            x.c = a;
            return x;
        }
    }
}

It would be awesome if somone could explain to me why this isn't casting properly.

Thanks

like image 958
Doren Roosje Avatar asked Aug 13 '12 12:08

Doren Roosje


2 Answers

Conversion operators only apply when the type is known statically; after all, generic methods need to use the exact same IL for every T - so it can't call your operator in some cases, and a type-check in others.

Additionally, because you've explicitly cast to object, it will never be used; a cast from object is always a simple unbox or type check.

An evil fix would be (and I don't like this):

        this.a.Add((T)(dynamic)"abc");
        this.a.Add((T)(dynamic)"def");
        this.a.Add((T)(dynamic)"ghi");

which defers the resolution to runtime. It works, but I would need to wash my eyes after that. More generally, though: operators and generics do not play nicely - so: try not to use that combination in your API. I really wouldn't use the above, personally!

like image 66
Marc Gravell Avatar answered Sep 23 '22 06:09

Marc Gravell


Compiler has no knowledge at compile time if generic parameter has explicit cast you are using.

You can introduce interface though, and put constrain on generic parameter

like image 44
vittore Avatar answered Sep 23 '22 06:09

vittore