Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# - Problem with generics and inheritance

I've got a problem with inheritance and generics. This is the code that illustrates my problem:

namespace TestApplication
{
    public class MyClass<T>
    {
        private T field;

        public MyClass(T field)
        {
            this.field = field;
        }
    }

    public class MyIntClass : MyClass<int>
    {
        public MyIntClass(int field)
            : base(field)
        {
        }
    }
}

And when I try to do something like this:

MyClass<int> sth = new MyClass<int>(10);
MyIntClass intsth = (MyIntClass) sth;

I receive cast exception: Invalid cast exception. Unable to cast 'TestApplication.MyClass`1[System.Int32]' to 'TestApplication.MyIntClass'.

What is more I cannot create cast operator:

public static implicit operator MyIntClass(MyClass<int> myClass)

because: 'TestApplication.MyIntClass.implicit operator TestApplication.MyIntClass(TestApplication.MyClass)': user-defined conversions to or from a base class are not allowed

I need to create casts as described above. I don't know why I cannot cast from a type that is the base class. How can I solve this problem? Thanks in advance.

Edit

Thanks for Your answers. Now I see that i cannot convert from a base class to derived class and i see that it doesn't have anything to do with generics. But why i cannot create user-defined conversions from a base class? I have a method that returns the base class. I am able to define a conversion method but creating a cast operator imho would be a better solution.

like image 529
empi Avatar asked Jan 11 '09 19:01

empi


2 Answers

You can only cast from a base class to a derived class if the object is actually of type derived class. I mean, you can't cast an instance of base (MyClass<int>) to MyIntClass. You can, however cast it if it was actually of type MyIntClass stored as an MyClass<int> instance.

MyClass<int> foo = new MyIntClass();
MyIntClass bar = (MyIntClass)foo; // this works.

Assume:

class Base {
   int x;
}

class Derived : Base {
   int y;
}

Base foo = new Base();
Derived bar = (Derived)foo;

if it was allowed, what would the value of bar.y be? In fact, converting from Derived to Base is not a conversion at all. It's just telling the compiler to let the variable of type Base to point to an object of type Derived. It is possible since derived has more or equal features than Base which is not the case in the other way around.

If you were able to create a conversion operator between base and derived classes, the C# compiler would be unable to distinguish it from the built in relationships defined for them. This is why you cannot create cast operators along inheritance hierarchies.

like image 120
mmx Avatar answered Oct 11 '22 13:10

mmx


The other answers so far are correct, but I'd like to point out that your example has nothing to do with generics. It's the equivalent of:

using System;

class Base {}
class Child : Base {}

class Test
{
    static void Main()
    {
        Base b = new Base();

        // This will throw an exception
        Child c = (Child) b; 
    }
}
like image 38
Jon Skeet Avatar answered Oct 11 '22 13:10

Jon Skeet