Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inheriting generics with inherited parameterizations

I am looking for a way to inherit generics with inherited parameterizations - or if that's not possible, the closest way to get the same functionality.

Consider the following:

Class B inherits from class A

Class D inherits from Class C

Now, I have one class:

abstract class A<T> where T : C

with constructor:

public A(T t)

Now, I wish to extend class A as so:

class B<D> : A<C>

Creating a constructor:

 public B(D t) : base(t){ /*stuff here*/}

However, this throws a compile-time error, since D is not C. So my two questions are:

a) Is there a clean way to do this? In the worst case scenario, I think I can replace D with C with little problem, but maybe there's a reason why that's not a safe idea?

b) Should I even be explicitly stating my generics in the child class definition, or is there a cleaner way I should do this with constrained types?

like image 657
user650261 Avatar asked Jul 24 '15 18:07

user650261


People also ask

Can generic types be inherited?

Generics also provide type safety (ensuring that an operation is being performed on the right type of data before executing that operation). Hierarchical classifications are allowed by Inheritance. Superclass is a class that is inherited. The subclass is a class that does inherit.

How do you extend a generic class in Java?

When generic type invocation happens, the T and E in extends MyGeneric<T, E> would be replaced by type arguments which replaces type parameters T and E in Extend1<T, E> . So, in fact, both generic and non-generic types can extends/implements non-generic types only.

What is subtyping in Java?

What is subtyping? Subtyping is a key feature of object-oriented programming languages such as Java. In Java, Sis a subtype of T if S extends or implements T. Subtyping is transitive, meaning that if R is a subtype of S, then R is also a subtype of T (T is the super type of both Sand R).

Why doesn't mygenericclass support inheritance?

The reason is that the CLR likes to be able to compile a single version of the code for MyGenericClass that will work for any reference type specified for T. It can do this for the second case, because it can quietly replace T with object and insert appropriate casts, roughly equivalent to: But for the inheritance version, that trick doesn't work.

Why do we need to create generic classes?

For example, when creating a generic class, you can oblige it to implement the functionality of a certain interface or you can make sure that the class is derived from a specific base class. This would make sure that the generic class surely contains some useful functionality.

How to create a constraint on a generic class in Java?

To create a constraint on a generic class, after the <TypeName> operator, type where TypeName : followed by the rule that the class must follow. For example, you may want the generic class to implement the functionality of a pre-defined class. You can create the generic class as follows:

What are the features of generics?

One of the features of generics is that you can create a class that must implement the functionality of a certain abstract class of your choice. For example, when creating a generic class, you can oblige it to implement the functionality of a certain interface or you can make sure that the class is derived from a specific base class.


1 Answers

Add a where constraint to class B

class B<D> : A<C> where D : C

To answer you questions:

a) With the fix in this answer, your approach is pretty clean so far, if a tad over abstract (due to the names mostly).

b) You should only be adding the D generic type parameter to your child class B if the child class itself is either adding value in a generic way related to subclasses of C which are instances of D; or if the child class is itself incomplete, is expected to be extended and requires knowledge subclasses of C as D. In which case, you should mark it abstract.

UPDATE:

I wanted to add one more thing about this. In the signature above, the T parameter of A<T> will be C in those members of A that use the T type. This may be a problem as demonstrated in the following example:

public class C {}

public class F : C {}

public class E : C {}

public class A<T> where T : C
{
    protected T cSubclass;
    public void SetCSubclass(T cSubclass) { this.cSubclass = cSubclass; }
}

public class B<D> : A<C> where D : C
{
    public D GetCSubclass()
    {
        return this.cSubclass;
    }
}

The code in this example will not compile. You will get the following compilation error:

error CS0266: Cannot implicitly convert type 'C' to 'D'. An explicit conversion exists (are you missing a cast?)

However the compilation error is resolved if we change class B to the following:

public class B<D> : A<D> where D : C
{
    public D GetCSubclass()
    {
        return this.cSubclass;
    }
}

The reason is that D is to be a specific subclass of C, however in the former version we've only constrained A to any form of C including itself and any of its subclasses. Therefore we could potentially call new B<F>.SetCSubclass(new E()); which would be a different type then what GetCSubclass would be expecting to return. In the latter version we've specified D as the type argument to use in A forcing B<F>.SetCSubclass to only accept instances of F.

This provides a further degree of type safety that a developer using this type of pattern may be expecting.

like image 167
Tyree Jackson Avatar answered Oct 06 '22 10:10

Tyree Jackson