How to handle generic inheritance - c#

I have this code for example
public class BaseClass
{}
public class DerivedClass1 : BaseClass
{}
public class DerivedClass2 : BaseClass
{ }
public class DerivedClass3 : BaseClass
{ }
public class GenericBaseClass<T> where T : BaseClass
{
public List<T> collection { get; set; }
}
Now I'd like to create a new class which would inherit from GenericBaseClass<T> and have somehow a collection List in this class.
Is this even possible this way ?
Because List<BaseClass> = new List<DerivedCLass3>(); isn't valid.
Or the only way to achieve this is to remove the collection property from the GenericBaseClass and add a collection List directly in the derived class.
I hope I expressed myself understandable as English isn't my first language :-)

public class GenericBaseClass<T> where T : BaseClass
{
public List<T> collection { get; set; }
}
public class GenericDerivedClass1 : GenericBaseClass<DerivedClass1>
{
// Here the collection property will be of type List<DerivedClass1>
}

The reason why your sample code can't compile is due to covariance. .Net can't handle auto typing of a class that is less specific than itself. I believe this is all changing in .Net 4.5 though and what you are trying to do may in fact be supported.
Covariance and contravariance (computer science)

Related

C# Generic Type Inheritence

Is it possible to create a generic class<T> which the generic type T will be the base class of it?
i.e:
MyClass<Base1> b1 = new MyClass<Base1>();
MyClass<Base2> b2 = new MyClass<Base2>();
b1.Name="test";
b2.ID=1;
Base Classes:
class Base1
{
protected string Name{ get; set;}
}
class Base2
{
protected int ID{ get; set;}
}
Inherited Class:
class MyClass<T>:T //here is the question is it possible dynamic inheritence
{
}
It's possible to use a constraint on T thus forcing T to be of type baseclass, like this:
public class baseclass
{
// base class code
}
// perfectly valid
public class derived1<T> : baseclass where T : baseclass
{
// derived class code
}
It's impossible to compile the following code, since T is a type parameter, and the compiler must infer it from usage. obviously that can't be done like this.
public class derived2<T> : T
{
// derived class code
}

Generics inheritance compile error

I'm getting a compile error when I try to compile this
The type 'WpfApplication2.CommandInstrumentTrade' cannot be used as type parameter 'T' in the generic type or method 'WpfApplication2.GenericWindowBase'. There is no implicit reference conversion from 'WpfApplication2.CommandInstrumentTrade' to 'WpfApplication2.GenericCommandBase'
public interface IBaseClass
{
int ID { get; set; }
}
public class BaseClass : IBaseClass
{
public int ID { get; set; }
}
public class DerivedClass : BaseClass
{
}
public class Command
{
}
public class GenericCommandBase<T> : Command where T : IBaseClass
{
}
public class DerivedGenericCommand : GenericCommandBase<DerivedClass>
{
}
public class GenericWindowBase<T> where T : GenericCommandBase<IBaseClass>
{
}
public class DerivedGenericWindow : GenericWindowBase<DerivedGenericCommand> // this line fails
{
}
The issue is that Generic<Derived> does not satisfy the condition where T : Generic<Base>. Even if Derived derives from Base, Generic<Derived> does not derive from Generic<Base>
There are many questions like that in StackOverflow.
Try reading those:
C# Generics Inheritance
generic inheritance in C#?
Inheritance doesn't compose with generics. You need to create some kind of converter from one to another. Maybe if you present some less abstract code we could help You

C# Generics - Classes implementing other generic classes

I have a
public class A<T> where T : IBase
{
//Does something
}
I need a second class that behaves like a collection of class A
public class B<A<T>> : IEnumerable<A<T>> where T : IBase
{
}
The problem is that I do not want to create classes like
public class B<A<MyCustomObjectP>> : IEnumerable<A<MyCustomObjectP>>
{
}
public class C<A<MyCustomObjectQ>> : IEnumerable<A<MyCustomObjectQ>>
{
}
and so on.. I would like to let the CustomObject be a generic type parameter that implements IBase.
I found that even doing this is illegal:
public class B<T, U> : IEnumerable<T> where T : A<U> where U : IBase
{
}
How could I achieve this type of behaviour, if this is illegal? Is there a better design pattern of sorts that might help?
The IBase constraint is defined on A<T>, so it must be defined again on all generic classes, that want to use A<U> (using U to distinguish from T in A<T> class definition, but it can be called anything). You should be able to do simply:
public class B<T> : IEnumerable<A<T>> where T : IBase { ... }
You wrote that you need a second class that behaves like a collection of class A.
Since you have other classes (like B) inheriting from IBase as well, which you want to add, you can make the collection a collection of IBase.
Hence the solution would look like this (note that I have used List but you can easily replace that by IEnumerable - but then you have to implement methods like .Add yourself):
void Main()
{
var items = new CollectionOf<IBase>(); // create list of IBase elements
items.Add(new A() { myProperty = "Hello" }); // create object of A and add it to list
items.Add(new B() { myProperty = "World" }); // create object of B and add it to list
foreach(var item in items)
{
Console.WriteLine(item.myProperty);
}
}
// this is the collection class you asked for
public class CollectionOf<U>: List<U>
where U: IBase
{
// collection class enumerating A
// note you could have used IEnumerable instead of List
}
public class A: IBase
{
// class A that implements IBase
public string myProperty { get; set; }
}
public class B: IBase
{
// class B that implements IBase too
public string myProperty { get; set; }
}
public interface IBase {
// some inteface
string myProperty { get; set; }
}

C# Derived Type to Generic List as Parameter

I am trying to do the following in C# 4.0:
I have a Base Class and 2 derived classes
public class Base {}
public class DerivedClass1 : Base {}
public class DerivedClass2 : Base {}
I want to do something like this, but it doesn't work.
How to I tell a Generic List to accept a Base Class and the derived classes of the base class.
public class Class_1
{
public Class_1()
{
List<DerivedClass2> list = new List<DerivedClass2>();
new Class_2(list);
}
}
public class Class_2
{
public Class_2(List<Base> list)
{
}
}
In Java I can do something like this
public class Class_2
{
public Class_2(List<? extends Base> list)
{
}
}
Does something like that exists in C#
I hope my question is clear, its just about the generics of the List.
Thanks a lot in Advance :)
General case:
function Foo<T>(List<T> list) where T : Base {
...
}
plus for interfaces and delegates, C# allows co/contravariance.
For e.g. IEnumerable<T> and IList<T>, your code will therefore work! Note that if this was allowed for List<T>s, you could insert a Derived1 into a list of Derived2s by using the common base class, which would break type safety. So simply stick to the above, readonly interfaces.
I think you mean either:
// Define other methods and classes here
public class Class_1
{
public Class_1()
{
List<DerivedClass2> list = new List<DerivedClass2>();
new Class_2<DerivedClass2>(list);
}
}
public class Class_2<T> where T : Base
{
public Class_2(List<T> list)
{
}
}
Or, if you want the constructor to be generic, and not the class:
// Define other methods and classes here
public class Class_1
{
public Class_1()
{
List<DerivedClass2> list = new List<DerivedClass2>();
Class_2.Create(list);
}
}
public class Class_2
{
public static Class_2 Create<T>(List<T> list) where T : Base
{
// Stuff
return new Class_2(/*Stuff*/);
}
public Class_2()
{
}
}

Really bizarre C# generics question

This code compiles but looks very strange.
I have a typical and simple parent/child relationship here which is implemented using generics in a very strange way.
But I can't seem to find any other way of doing it.
class SampleObject<T> //I don't want to make this a generic but am forced to
{
//The SampleContainer this object is in
//This must be located in this base class
public SampleContainer<T> Parent { get; set; }
}
class SpecificObject : SampleObject<SpecificObject>
//SampleObject<SpecificObject> !!? This is the bizzare bit
//It seems really strange but necessary for compilation to work
{
}
//A class to contain a List of objects derived from SampleObjects
class SampleContainer<T>
{
public List<T> List;
}
class Start
{
public void Test()
{
SampleContainer<SpecificObject> container = new SampleContainer<SpecificObject>();
SpecificObject o = new SpecificObject(); //create an object
container.List.Add(o); //add it to the list
o.Parent = container; //set its parent
}
}
Can this code be simplified?
This seems to work without the type.
Is this what you were looking for?
class SampleObject //I don't want to make this a generic but am forced to
{
//The SampleContainer this object is in
//This must be located in this base class
public SampleContainer<SampleObject> Parent;//{ get; set; }
}
class SpecificObject : SampleObject
//SampleObject<SpecificObject> !!? This is the bizzare bit
//It seems really strange but necessary for compilation to work
{
}
//A class to contain a List of objects derived from SampleObjects
class SampleContainer<T>
{
public List<T> List;
}
class Start
{
public void Test()
{
SampleContainer<SampleObject> container = new SampleContainer<SampleObject>();
SpecificObject o = new SpecificObject(); //create an object
container.List.Add(o); //add it to the list
o.Parent = container; //set its parent
}
}
In the MSDN documentation, it states that:
When deriving from a generic base
class, you must provide a type
argument instead of the base-class's
generic type parameter:
public class BaseClass<T>
{...}
public class SubClass : BaseClass<int>
{...}
It's probably a constraint that the C# designers set up in the compiler. They require that a derived type must specify the type of the generic argument at compile time. I'm not quite sure why.
Generics can create some unwieldy class hierarchies. However, the syntax for SpecificObject : SampleObject does make sense, since you're stating that the object has a parent relationship. The only other way I could see you do this, would be to split out the hierarchy with an interface. It doesn't buy much, but it may help clarify the intent.
interface IHasParent<T>
{
T Parent { get; set; }
}
public class SpecificObject : IHasParent<SpecificObject>
{
public SpecificObject Parent { get; set; }
}
If you're concerned about how verbose your collection is, you can tame the angle brackets a bit by using:
public SpecificObjectContainer : Container<SpecificObject>
{
}

Categories

Resources