Reputation: 2265
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?
Upvotes: 6
Views: 98
Reputation: 2608
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.
Upvotes: 2