I am trying to get to grips with more complicated inheritance structures and generics and I am trying to create some architecture for a current project which is following this suit. My problem currently is I am getting this error:
Type argument 'Foo' does not inherit from or implement the constraint type 'ListBase'
public class ItemBase {}
public class ListBase<T> where T : ItemBase
{
public virtual List<T> ListExample {get; set; }
}
These are my base classes, although they probably aren't named appropriately I have just tried to show a simple example of what I am trying to achieve.
public class FooItem : ItemBase { }
public class Foo : ListBase<FooItem>
{
public override List<FooItem> ListExample { get; set;}
}
So I can then extend the initial base class for the lists and do more with it, but I want a generic way of handling all of these classes.
public class ListHandler<T> where T : ListBase<ItemBase> { }
When I try to pass Foo as T to the ListHandler I get the error mentioned, I thought that inevitably because Foo is a List<ItemBase> and FooItem is of type ItemBase I would be able to do this var handler = new ListHandler<Foo>();.
Could anybody explain why I can't do this or what I am doing wrong?
A ListBase<ItemBase> is not the same as a ListBase<FooItem>.
In particular, you can add any kind of ItemBase to a ListBase<ItemBase>.
You need to accept two generic parameters:
public class ListHandler<TList, TItem> where T : ListBase<TItem> where TItem : ItemBase { }
You need to supply the type parameter of the item type, not the list type. To clarify this, try expanding the ListHandler class to include an AddItem method which adds a ItemBase item to a ListBase instance:
// As is: Won't work, because there is no way to refer to the constructed
// specific type of ItemBase:
public class ListHandler<TList> where TList: ListBase {
public TList List { get; private set; }
public ListHandler(TList List) { this.List = List; }
public void AddItem(T???? item) { List.ListExample.Add(item); }
}
// Corrected: this will work because TItem can be used to constrain
// the constructed ListBase type as well:
public class ListHandler<TItem> where TItem : ItemBase {
public ListBase<TItem> List { get; private set; }
public ListHandler(ListBase<TItem> List) { this.List = List; }
public void AddItem(TItem item) { List.ListExample.Add(item); }
}
// And this will work just fine:
var handler = new ListHandler<FooItem>(new FooList());
Related
lately I started to learn generics. I run into trouble with storing references to generic classes instances. As you can see, my class ListHandler can store references to specific type of BaseClass. I would love to register BaseClass instances by themselves, which is why I wanted to guarantee that they will use BaseParamClass by adding 'where'. Anyway - it does not compile.'This', does not know that T is actually BaseClassParam even with 'where' keyword in class. I don't know what is wrong here and I couldn't find answer anywhere. I would be grateful for tips/guides/solutions.
public class ListHandler
{
private List<BaseClass<BaseParamClass>> list;
public ListHandler()
{
list = new List<BaseClass<BaseParamClass>>();
}
public void Register(BaseClass<BaseParamClass> param)
{
list.Add(param);
}
}
public class BaseClass<T> where T : BaseParamClass
{
private ListHandler listHandler;
public T Param { get; private set; }
public BaseClass(ListHandler listHandler)
{
this.listHandler = listHandler;
listHandler.Register(this); //throws error
}
}
Why don't you make ListHandler generic as well?
public class ListHandler<T>
{
private List<BaseClass<T>> list;
public ListHandler()
{
list = new List<BaseClass<T>>();
}
public void Register(BaseClass<T> param)
{
list.Add(param);
}
}
public class BaseClass<T>
{
private ListHandler<T> listHandler;
public T Param { get; private set; }
public BaseClass(ListHandler<T> listHandler)
{
this.listHandler = listHandler;
listHandler.Register(this);
}
}
Also, it seems strange to me to have BaseClass<T> contain a reference to a class that has a reference to BaseClass<T> itself.
I have another option for you.
Let's split the BaseClass<T> class into two with a non-generic base, like so:
public class BaseClass
{
protected ListHandler listHandler;
public BaseClass(ListHandler listHandler)
{
this.listHandler = listHandler;
}
}
public class BaseClass<T> : BaseClass where T : BaseParamClass
{
public T Param { get; private set; }
public BaseClass(ListHandler listHandler)
: base(listHandler)
{
listHandler.Register(this); // Compiles nicely! Yay!
}
}
Now, the list inside ListHandler can be defined as private List<BaseClass> list;. That means there is no problem adding any BaseClass item to the list. We also can then define two methods for registering and fetching generic versions of the BaseClass<T> from the ListHandler. It would look like this:
public class ListHandler
{
private List<BaseClass> list;
public ListHandler()
{
list = new List<BaseClass>();
}
public void Register<T>(BaseClass<T> param) where T : BaseParamClass
{
list.Add(param);
}
public BaseClass<T> Fetch<T>() where T : BaseParamClass
{
return list.Select(x => x as BaseClass<T>).Where(x => x != null).FirstOrDefault();
}
}
So, given a class public class FooParam : BaseParamClass { } I can write this code:
ListHandler listHandler = new ListHandler();
BaseClass<FooParam> baseClass = new BaseClass<FooParam>(listHandler);
BaseClass<FooParam> baseClass2 = listHandler.Fetch<FooParam>();
Console.WriteLine(object.ReferenceEquals(baseClass, baseClass2));
The result from this code is True is written to the console - which means I can successfully fetch the instance of BaseClass<FooParam> from the ListHandler.
Why your code doesn't compile
In order to fully understand why your code doesn't compile, you'll have to dive into covariance and contravariance, which is a big topic and hard to explain in an SO answer. It can be especially confusing if you've gotten to a point where inheritance polymorphism is second nature to you; the rules are just different enough to be make your head hurt.
Here is what is confusing--
You're used to doing this:
object a = new String(...);
But generics don't let you do this!
List<object> c = new List<string>(); //Compiler error
That's because those two Lists are not related the same way that object and string are related. One does not inherit from the other. Rather, they are different variants of a generic type definition. In the generic world, you can't assign one to the other. The same is true of this:
void Foo<T>() where T: BaseParamClass
{
BaseClass<BaseParamClass> a = new BaseClass<T>(); //Compiler error
}
In this example, T could be BaseParamClass or one of its derived types. They are not the same type. So to remain type-safe, the compiler has to disallow this assignment, and your Register call, which has the same type mismatch.
Standard ways around this
You need a covariant interface. These allow assignment from derived to base. So for example, while this is still illegal:
List<object> a = new List<string>(); //Compiler error
This is totally fine:
IEnumerable<object> e = new List<string>(); //Is OK
Because IEnumerable was declared to be covariant, like this:
interface IEnumerable<out T>
Which means it is can be assigned in this way. It works because using out also adds a compiler constraint to the interface: it can be used to retrieve stuff...
interface IEnumerable<out T>
{
T Item[int index];
}
...but it cannot accept anything:
interface IEnumerable<out T>
{
Add(T item); //Compiler error
}
These constraints are what allow generics to provide early-bound type safety while still allowing certain forms of (non-inheritance) polymorphism.
What I'd suggest
Based on your comment, it sounds like you just need a container (a stack, apparently) that can hold references to these BaseClass<T> instances. If you are following separation of concerns, the stack doesn't need to actually do anything with the T, other than store it and retrieve it, and to allow it to register itself.
Since that is a separate concern, make a separate interface.
And in the interest of keeping things simple, maybe avoid using generics completely for this bit.
One way to do it--
Create an interface that allows access to everything the stack needs to know about an item it is containing. For example, if the stack contains popups of various kinds, you may want to expose the popup's title.
interface IStackable
{
string Title { get; set; }
}
Now use it like this:
public class ListHandler
{
private readonly Dictionary<string, IStackable> list;
public ListHandler()
{
list = new Dictionary<string, IStackable>();
}
public void Register(IStackable item)
{
list.Add(item.Title, item);
}
}
public class BaseClass<T> : IStackable where T : BaseParamClass
{
private ListHandler listHandler;
public T Param { get; private set; }
public BaseClass(ListHandler listHandler)
{
this.listHandler = listHandler;
listHandler.Register(this);
}
public string Title { get; set; }
}
Unless there is some other requirement, you shouldn't need to make it any more complicated than that.
All you really need to do is add an interface. This works:
public class BaseParamClass
{
}
public class ListHandler
{
private List<IBase<BaseParamClass>> list;
public ListHandler()
{
list = new List<IBase<BaseParamClass>>();
}
public void Register(IBase<BaseParamClass> param)
{
list.Add(param);
}
}
public interface IBase<T> where T : BaseParamClass
{
T Param {get; }
}
public class BaseClass : IBase<BaseParamClass>
{
private ListHandler listHandler;
public BaseParamClass Param { get; private set; }
public BaseClass(ListHandler listHandler)
{
this.listHandler = listHandler;
listHandler.Register(this);
}
}
Working code on DotNetFiddle
I have three classes, two of which inherit from a base class, and the third which I would like to reference one of the other two depending on the state of the application.
public class Batch
{
public Batch() { }
}
public class RequestBatch : Batch
{
public RequestBatch(string batchJobType) : base(batchJobType) { }
public override int RecordCount
{
get { return Lines.Count; }
}
}
public class ResponseBatch : Batch
{
public ResponseBatch(string batchJobType) : base(batchJobType) { }
public ResponseBatch(int BatchJobRunID)
{ }
}
Sometimes I have an instance of Child1 instantiated, and sometimes I need Child2. However, I have model that I want to pass around my application to keep everything in one place, but I want a way to make the property that holds Child1 and Child2 generic, for example:
public class BatchJob {
public List<Batch> Batches { get; set; }
}
And then later do this
public List<RequestBatch> GetBatches(...) {}
var BatchJob = new BatchJob();
BatchJob.Batches = GetBatches(...);
However, the compiler yells at me saying it can't implicitly convert Child1 to (its base type) Parent.
I get red squiggles under "= GetBatches(...." saying "Cannot implicitly convert type 'System.Collections.Generic.List' to 'System.Collections.Generic.List'
Is there a way to generify the Property so it can take any abstract of type Parent?
Thanks!
The code snipped you show does work. There is no compiler error:
class Program
{
static void Main()
{
var rj = new RunningJob();
rj.Property = new Child1();
rj.Property = new Child2();
}
}
public class RunningJob {
public Parent Property { get; set; }
}
public class Parent { }
public class Child1 : Parent { }
public class Child2 : Parent { }
The only issue that comes with this code is that Property is of type Parent. So you cannot call methods that are specific for Child1/Child2. This can be done using constraints on generic type parameters on class RunningJob :
public class RunningJob<TParent> where TParent : Parent
{
public TParent Property { get; set; }
}
Hence, now it is ensured that Property is of type Parent or any derived types.
One option...
public new IEnumerable<RequestBatch> GetBatches(...) {
get
{
return base.GetBatches(...).OfType<RequestBatch>();
}
}
Another...
If you don't need to modify the collection then just change from List<T> to IEnumerable<T>
More Info...
Covariance and Contravariance in Generics
A contravariance conundrum
I've been trying to do something which I hoped would be simple, but turned otherwise.
I have a base class:
public class EntityBase
{
}
and two classes that inherit from it:
public class EntityA : EntityBase
{
}
public class EntityB : EntityBase
{
}
I want to use a container type that will wrap
An instance of EntityBase
A number of children which are other instances of the container type.
I want this container expose the exact type of the EntityBase instance it contains, so I use C# generics. But I could not manage to convince C# compiler to define a list of the container type (which has a type parameter now):
public class EntityNode<T> where T : EntityBase
{
private T _node;
private List<EntityNode<EntityBase>> _children = new List<EntityNode<EntityBase>>();
public EntityNode(T pNode)
{
_node = pNode;
}
public void AddChild(EntityNode<T> pNode)
{
//_children.Add(pNode); //this is not going to work...
}
public T Root
{
get { return _node; }
set { _node = value; }
}
}
Is it possible to allow EntityNode to contain a list which in turn contains EntityNode<EntityA>, EntityNode<EntityB> and EntityNode<EntityBase> instances?
What about using List<EntityNode<T>> instead of List<EntityNode<EntityBase>>:
private List<EntityNode<T>> _children = new List<EntityNode<T>>();
I've a Generic type, which is used to give some meta data on an object to persist:
public class PersistedElementDefinition<T> where T: IPersistedObject{
List<PersistedPropertyDefinition<T>> PropertiesToPersist {get;set;}
}
public class PersistedPropertyDefinition<T> where T: IPersistedObject{
public Func<T, object> PropertyGetter{get;set;}
public Action<T, object> PropertySetter {get;set;}
}
and I've my IPersistedObject which can give his definition
public interface IPersistedObject{
PersistedElementDefinition<TypeOfTheImplementingType> Definition {get;}
}
The idea is that if I implement IPersistedObject I should implement it like this:
public class MyPersistedObject:IPersistedObject{
PersistedElementDefinition<MyPersistedObject> Definition{get;}
}
When I persist my class have the following thing:
I can't do the following:
public interface IPersistedObject<T>{
PersistedElementDefinition<T> Definition {get;}
}
because:
It would allow to have a MyPersistedObject<SomeOtherObject
At some point I receive an object, and I should be able to see if it implements the IPersistedObject and do some custom action with it.
For the 2, here is an example of what kind of issue I'm facing if I've a Generic interface:
public void Persist<T>(T objectToPersist)where T:IPersistedObject{
...
foreach(PersistedPropertyDefinition<T> property in objectToPersist.PropertiesToPersist){
object objectToSerialize = property.ObjectGetter(objectToPersist);
if(objectToSerialize is IPersistedObject<___Don't know how to put something generic here___>){
Persist((IPersistedObject<___Don't know how to put something generic here___>)objectToSerialize);
}
}
...
}
Is there a possibility in c# to declare an interface with a generic property of the implementing type?
You can use the curiously recurring template pattern to lock this down a bit further. It isn't bulletproof, but assuming you're not a masochist, and you don't mind the fact that it is theoretically possible to create nonsensical implementations of the interface that violate the invariants you are trying to guarantee, you can do this:
public interface IPersistedObject<T> where T : IPersistedObject<T>
{
PersistedElementDefinition<T> Definition {get;}
}
public class PersistedElementDefinition<T> where T: IPersistedObject<T>
{
...
}
public class MyPersistedObject : IPersistedObject<MyPersistedObject>
{
// Here, you are forced to implement a PersistedElementDefinition<MyPersistedObject>,
// which presumably is the reason behind this whole song and dance
PersistedDefinition<MyPersistedObject> Definition { get; }
}
The problem with this, as you noticed at the outset, is that you could simply define public class MyPersistedObject : IPersistedObject<MyOtherPersistedObject>, and end up breaking the contract you are trying to cobble together, which in plain words is the following:
A persisted object must have a gettable definition that is a persisted element definition of its own type
The C# type system is simply not equipped to handle this elegantly. My advice is to get out early, change to object or dynamic where possible and learn to live with the loss of certain compile time guarantees.
Assuming you're willing to sacrifice some compile time safety, you could do things like so:
class Program
{
static void Main(string[] args)
{
var mpo = new MyPersistedObject();
var ptp = mpo.Definition.PropertiesToPersist;
}
}
public class PersistedElementDefinition<T> where T : IPersistedObject
{
private readonly List<PersistedPropertyDefinition<T>> _propsToPersist = new List<PersistedPropertyDefinition<T>>();
public List<PersistedPropertyDefinition<T>> PropertiesToPersist
{
get { return _propsToPersist; }
}
}
public class PersistedPropertyDefinition<T> where T : IPersistedObject
{
public Func<T, object> PropertyGetter { get; set; }
public Action<T, object> PropertySetter { get; set; }
}
public interface IPersistedObject
{
dynamic Definition { get; }
}
public class MyPersistedObject : IPersistedObject
{
private readonly PersistedElementDefinition<MyPersistedObject> _definition = new PersistedElementDefinition<MyPersistedObject>();
public dynamic Definition { get { return _definition; } }
}
I've got a handy collection in my middle tier which is for collections of child things that belong to a parent thing.
public class ChildCollection<TParent, TChild>
{
public IEnumerable<TChild> GetChildren();
etc.
}
In the interface, I've got a handy grid that can display the contents of a ChildCollection<TParent,TChild> and let users do work on it.
public abstract class ChildCollectionGrid<TCollection, TParent, TChild> : MyGridControl
where TCollection : ChildCollection<TParent, TChild>
{
public abstract TCollection Collection;
etc.
}
Inheriting this class to make a grid to work with the Waffles on a Widget ends up looking like this.
public class WidgetWafflesGrid : ChildCollectionGrid<WidgetWafflesCollection, Widget, Waffle>
This is a little redundant. A WidgetWaffleCollection is a ChildCollection<Widget,Waffle>. With that first generic type argument specified, the class won't compile unless you specify exactly those two others.
Is there a prettier way to accomplish this where the compiler could infer those other two types? I know I'm being finicky but ideally I would like to have the class declaration look like:
public class WidgetWafflesGrid : ChildCollectionGrid<WidgetWafflesCollection>
Thanks for your help!
No, there's not. Generic parameter inference works only on methods.
Why derive from your collection? Just keep it like:
public abstract class ChildCollectionGrid<TParent, TChild> : MyGridControl
{
public abstract ChildCollection<TParent, TChild> Collection;
etc.
}
public class WidgetWafflesGrid : ChildCollectionGrid<Widget, Waffle>
{
}
The only way to handle inheritance in collections with Generics is using the Collection<TCollection,TChild> : where TCollection : Collection<TCollection,TChild> { } pattern.
Here is an example with a concrete class
public abstract class Collection<TCollection, TChild>
where TCollection : Collection<TCollection, TChild>, new()
{
protected Collection()
{
List=new List<TChild>();
}
protected List<TChild> List { get; set; }
public TCollection Where(Func<TChild, bool> predicate)
{
var result=new TCollection();
result.List.AddRange(List.Where(predicate));
return result;
}
public void Add(TChild item) { List.Add(item); }
public void AddRange(IEnumerable<TChild> collection) { List.AddRange(collection); }
}
public class Waffle
{
public double Temperature { get; set; }
}
public class WafflesCollection : Collection<WafflesCollection, Waffle>
{
public WafflesCollection BurnedWaffles
{
get
{
return Where((w) => w.Temperature>108);
}
}
}
class Program
{
static void Main(string[] args)
{
WafflesCollection waffles=new WafflesCollection();
// Count = 3
waffles.Add(new Waffle() { Temperature=100 });
waffles.Add(new Waffle() { Temperature=120 });
waffles.Add(new Waffle() { Temperature=105 });
var burned=waffles.BurnedWaffles;
// Count = 1
}
}