Create list of generics - c#

I have base class for my entities
public class Entity<T> where T : Entity<T>, new()
{
public XElement ToXElement()
{
}
public static T FromXElement(XElement x)
{
}
}
I have to use this strange construction Entity<T> where T : Entity<T>, because i want static method FromXElement to be strongly-typed
Also, i have some entities, like that
public class Category : Entity<Category>
{
}
public class Collection : Entity<Collection>
{
}
How can i create a generic list of my entities, using base class?
var list = new List<Entity<?>>();
list.Add(new Category());
list.Add(new Collection());

You can't with that definition. There is no "common base class" between Category and Collection (other than object, of course).
If there were, say if Entity<T> were defined as:
public class Entity
{
}
public class Entity<T> : Entity where T : Entity<T>, new()
{
public XElement ToXElement()
{
}
public static T FromXElement(XElement x)
{
}
}
then you could do
var list = new List<Entity>();
list.Add(new Category());
list.Add(new Collection());
But what would that buy you?

Create a marker interface:
public interface IAmAGenericEntity { }
public class Entity<T> where T : IAmAGenericEntity, new()
// ...
public class Category : Entity<T>, IAmAGenericEntity
// ....
var list = new List<IAmAGenericEntity>();
// ...

From the lack of an abstract marker on Entity, I assume that To/FromXElement use reflection and should work for any subtype of Entity. I recommend that you structure your classes as follows:
public class Entity
{
public XElement ToXElement() { ... }
protected static T FromXElement<T>(XElement x)
where T : Entity
{
...
}
}
public class Category : Entity
{
public static Category : FromXElement(XElement x)
{
return FromXElement<Category>(x);
}
}
The "boilerplate" is minimal, and it doesn't require that you creatively circumvent the type system. You don't have to worry about the lack of a common base, or about manual conversions. If you like, you can eliminate the boilerplate entirely and just construct your objects directly from Entity:
public class Entity
{
public XElement ToXElement() { ... }
public static T FromXElement<T>(XElement x)
where T : Entity
{
...
}
}
In essence, what you're doing is implementing a type class, which C# does not directly support. There are a number of ways to work around this lack, but I usually find them to be more trouble than they're worth, especially when it comes to static methods. If C# supported static extension methods, it would be simple, but alas it does not.

You can define a non-generic class to be the base class of all entity classes
public class Entity
{
}
and make Entity inherit Entity
public class Entity<T> : Entity where T : Entity<T>, new()
{
}
Now you can create the list of entities as:
var list = new List<Entity>();

You can solve this problem by adding a non-generic version of the class
class Entity
{
// methods
public T As<T>()
{
if (this is T) return (T)this;
throw new InvalidCastException();
}
}
class Entity<T> : Entity where T : Entity<T>, new()
class Cathegory : Entity<T> {}
and then create the list of the base class:
var list = new List<Entity>()
list.Add(new Cathegory());
Then, if you want to call a "generic specific" operation, you need to call the "As" function or simply cast the object.

Related

C# generic type containing a list of itself when the type parameter is a base class

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>>();

Generics: can an interface be interogated to find T

I have completely re-written this hoping to make my question clearer. I have chosen the concept of services making use of repositories in my example code.
Example code:
class Program
{
interface IEntity
{
int Id { get; set; }
}
// Example entity could be:
class Book : IEntity
{
public int Id { get; set; }
}
class Magazine : IEntity
{
public int Id { get; set; }
}
interface IRepository<TEntity> where TEntity : class, IEntity
{
IEnumerable<TEntity> GetEntities();
}
interface IBooksRepository : IRepository<Book> { }
interface IMagazineRepository : IRepository<Magazine> { }
class DataStore<TEntity> where TEntity: class, IEntity
{
public IEnumerable<TEntity> GetFromStore()
{
throw new NotImplementedException();
}
}
abstract class RepositoryBase<TEntity> : IRepository<TEntity>
where TEntity : class, IEntity
{
DataStore<TEntity> _dataStore;
public RepositoryBase()
{
_dataStore = new DataStore<TEntity>();
}
public IEnumerable<TEntity> GetEntities()
{
return _dataStore.GetFromStore();
}
}
class BookRepository : RepositoryBase<Book>, IBooksRepository { }
class MagazineRepository : RepositoryBase<Magazine>, IMagazineRepository { }
abstract class ServiceBase<IEntityRepository, TEntity>
where IEntityRepository : IRepository<TEntity>
where TEntity : class, IEntity
{
IEntityRepository _repository;
public ServiceBase(IEntityRepository repository)
{
_repository = repository;
}
public IEnumerable<TEntity> GetEntitiesFromRepository()
{
return new List<TEntity>();
}
}
class BookService : ServiceBase<IBooksRepository, Book>
{
public BookService(IBooksRepository bookRepository)
: base(bookRepository)
{ }
}
class MagazineService : ServiceBase<IMagazineRepository, Magazine>
{
public MagazineService(IMagazineRepository magazineRepository)
: base(magazineRepository)
{ }
}
static void Main(string[] args)
{
var aBookService = new BookService(new BookRepository());
var aMagazineService = new MagazineService(new MagazineRepository());
var books = aBookService.GetEntitiesFromRepository();
var magazines = aMagazineService.GetEntitiesFromRepository();
}
}
This all works fine and perhaps it is valid to ask why I want to change this. Mainly I am just curious if I can make this more neat. It is more a point of curiosity that one of functional correctness I suppose.
Both IBookRepository and IMagazineRepository know which concreate type they represent 'Book' and 'Magazine'
When I define my concreate services: BookService and MagazineService I have to specify the type as well as the interface:
class BookService : ServiceBase<IBooksRepository, Book>{}
class MagazineService : ServiceBase<IMagazineRepository, Magazine>{}
I wondered if I could simplify thier signatures as the Interfaces already know The type I am expecting Book or Magazine.
Can I extract the Entity Type from the inteface such that I no longer need to specify the type when creating concreate service types?
As I pondered this, I discovered a deeper issue with my knowledge of C#:
What exactly is the type of 'thing' that the generic system is looking for between those angle brackets: IEnumerable<TThisThing>.
When I look at intellisense is says T is the type of objects to enumerate.
So as an experiment I grabbed the type of MyType:
Type typeOfMyType = instanceOfMyType.GetType();
IEnumerable<typeOfMyType> enumerable = new List<typeOfMyType>(); //crude example.
Now of course this does not work. So what kind of thing is TThisThing that works between the angle brackets?
is there a way of extracting this information so that I can forgo the
inclusion of 'MyType' in the class definition and use the discovered
TMyType in the example method?
Yes, you simply need to define the generic type parameter in the methods name:
public IEnumerable<TMyType> GetMyTypes<TMyType>()
{
// get list of TMyType instances;
return list;
}
If you don't want to use a generic type parameter at all, you'll have to defer to reflection, and you won't be able to use a compile-time generic type such as returning an IEnumerable<T>.
So what kind of thing is TThisThing that works between the angle
brackets?
TThisThing should be a compile-time known type parameter. When you use Type typeOfMyType = instanceOfMyType.GetType();, the type of instanceOfMyType is only known at run-time.
For example:
var obj = new SomeClass<Foo>();
IEnumerable<Bar> bars = obj.GetMyTypes<Bar>();
Where Foo and Bar:
public class Foo { }
public class Bar { }

Can Generics in base class be specified in the parent class

I have a base class that has methods that use a generic type in C#, I then have other classes that inherit from these, I want to specify the type in the parent class to avoid angle brackets everywhere...
Here's a sample method from my base class class CBaseHome
public List<T> fetchAll<T>(CBaseDb db, bool includeEmpty = true) where T : CBaseTable, new()
{
List<T> retVal = new List<T>();
...
return retVal;
}
I the have a parent class that inherits from this class, (without overriding this function)
In the class that then consumes this I have the following code...
List<student> students = new limxpoDB.Home.student().fetchAll<student>(db, false);
so the Home.student class here inherits the CBaseHome class, and student inherits the CBaseTable...
I'd like to be able to say in the Home.student class that the only valid generic type for that class is student so that my consuming code looks like...
List<student> students = new limxpoDB.Home.student().fetchAll(db, false);
I realise here that the difference is minute, but I also use this library in some VB>Net code where it looks terrible...
Any ideas?
Thanks
Generic type parameters on a method cannot be imposed by a child class. So if I have:
public class Parent {
public List<T> GetStuff<T>() { ... }
}
I can not do:
public class Child : Parent {
// This is not legal, and there is no legal equivalent.
public List<ChildStuff> GetStuff<ChildStuff>() { ... }
}
What you can do is make the parent class generic, rather than it's method:
public class Parent<T> {
public List<T> GetStuff() { ... }
}
public class Child : Parent<ChildStuff> {
// GetStuff for Child now automatically returns List<ChildStuff>
}

Where() at abstract level to return new self

I have this code and I want to keep it elegant.
I got stuck at this inheriting issue and I would have to mess up the code if I do.
Help me keep it elegant. I don't mind making changes anywhere up and down the hierarchy; feel free to change the core.
I have these abstract classes (I omitted unrelated implementation to keep the question content short).
public abstract class Entity : IComparable
{
protected int _ID;
public abstract int ID { get; }
}
public abstract class SortedEntities<T> : IEnumerable<T> where T : Entity
{
Dictionary<int,T> _Entities;
}
And, obviously, an example of inheritance is as follows:
public class Contact : Entity { }
public class Contacts : SortedEntities<Contact> { }
And I also have more than just Contact and Contacts that inherit from Entity and SortedEntities that all act in the same manner.
At some point in my app, I want to select entities based on and ID list.
A sample code of what I want is:
Contacts LoadedContacts = new Contacts(); // load and fill somewhere else
// !!!NOT IMPLEMENTED YET!!!
Contacts SelectedContacts = LoadedContacts.GetFromIDList("1,4,7");
Where it returns a new Contacts object filled with those Contact objects of the ID's provided.
So, to allow that code for all classes inheriting from SortedEntities, I thought of adding this imaginative code to the abstract:
public abstract class SortedEntities<T> : IEnumerable<T> where T : Entity
{
// !!!NOT REAL CODE YET!!!
public abstract this<T> GetFromIDList(string IDCSV)
{
List<string> idlist = IDCSV.Split(',').ToList<string>();
return this.Where(entity => idlist.Contains(entity.ID.ToString()));
}
}
But obviously the this<T> is not allowed.
What I'm trying to tell the compiler is to make the return type of this method that of the inheriting class down the hierarchy.
That way, if someone calls LoadedContacts.GetFromIDList("1,4,7") it will return Contacts without having to cast it from SortedEntities<T> if I make it the return type, which would also require me to override the method in each inheriting class to hide the abstract method.
Am I forgetting something I already know?
Or is this completely not possible and I have to override and hide the method down the hierarchy for all inheriting classes?
A common solution is to add another generic type parameter that refers to the "current" type (like this refers to the "current" object):
public abstract class Entity : IComparable
{
protected int _ID;
public abstract int ID { get; }
}
public abstract class SortedEntities<TEntities, TEntity> : IEnumerable<TEntity>
where TEntities : SortedEntities<TEntities, TEntity>, new()
where TEntity : Entity
{
Dictionary<int, TEntity> _Entities;
public TEntities GetFromIDList(string IDCSV)
{
List<string> ids = IDCSV.Split(',').ToList<string>();
return new TEntities
{
_Entities = this.Where(entity => ids.Contains(entity.ID.ToString()))
.ToDictionary(e => e.ID)
};
}
}
Usage:
public class Contact : Entity
{
}
public class Contacts : SortedEntities<Contacts, Contact>
{
}
Note how the TEntities is restricted to a SortedEntities<TEntities, TEntity>. This does not really mean that TEntities can only refer to the current class, but as long as you follow the pattern of letting class X inherit from SortedEntities<X, Y>, it should work.
The new() constraint is required so you can instantiate a new instance of the "current" class.
Eric Lippert has indicated somewhere else that he dislikes this pattern. Act at your own risk!

Creating a collection for a base type with methods that will work on all inherited objects?

I'm currently starting a new project and I've run into a bit of a readblock. I'm hoping someone can help me out and I'll do my best to describe the problem.
I have a base abstract class called "EntityBase". From this class there are around 100 or so inherited classes. EntityBase has a number of methods such as Load() and Save() that are common to all my inherited classes. It also has a couple of constructors that accept either an integer or an IDataReader which are used to load the object from the database.
That's all working quite well.
Enter my new base class, named EntityCollectionBase which extends List<EntityBase>. I'm trying to write a Load function for it but I'm not sure how to proceed. Hopefully this bit of code can better illustrate my goal:
public bool Load()
{
bool result = true;
using (IDataReader reader = _dbManager.ExectureReaderSProc(this.LoadProcedure, new SqlParameter[] { new SqlParameter("#parentId", _parentID) }))
{
this.Add(new EntityBase(reader)); // WON'T WORK, EntityBase IS ABSTRACT
}
return result;
}
As you can see, I need the Load function to work in a generic manner to handle anything extending EntityBase, but because EntityBase is abstract, I cannot instanciate it.
Any ideas?
Thanks,
Sonny
Whenever you create an instance of one of several possible classes based on runtime data, a factory is the answer:
public interface IEntityFactory
{
EntityBase CreateEntity(IDataReader reader);
}
You would modify the loading class to accept one:
private readonly IEntityFactory _entityFactory;
public Loader(IEntityFactory entityFactory)
{
_entityFactory = entityFactory;
}
Then you would use the factory in the Load method:
public void Load()
{
using(var reader = _dbManager.ExectureReaderSProc(this.LoadProcedure, new SqlParameter[] { new SqlParameter("#parentId", _parentID) }))
{
Add(_entityFactory.CreateEntity(reader));
}
}
You'll need to use reflection to access a constructor taking an IDataReader. Your current example also only loads one item, which probably isn't what you want when loading a collection:
public class EntityCollectionBase<T> where T : EntityBase
{
public void Load()
{
var constructorInfo = typeof(T).GetConstructor(new[] { typeof(IDataReader) });
using(IDataReader reader = ...)
{
while(reader.Read())
{
T entity = (T)constructorInfo.Invoke(new object[] { reader });
this.Add(entity);
}
}
}
}
I'd consider making this static since the collection could be left in an invalid state if the IDataReader throws an exception while being loaded:
public static EntityCollectionBase<T> Load() { ... }
Give your EntityBase a void SetReader(IDataReader) method, and make sure all your entities have a default constructor.
public bool Load<T>() where T : EntityBase, new()
{
...
using (IDataReader reader = _dbManager.ExectureReaderSProc(
this.LoadProcedure, new SqlParameter[] {new SqlParameter("#parentId", _parentID) })) {
EntityBase entity = new T();
entity.SetReader(reader);
this.Add(entity);
}
...
}
I would perhaps go for a generic collection class contrained to EntityBase, and then you could instantiate and add objects in the following manner. However, this code assumes you have a constructor which accepts an integer parameter. If it does not, this code will properly blow up.
class EntityCollectionBase<T> : List<T> where T : EntityBase
{
public void Load()
{
// example
int someId = 14;
T t = (T)Activator.CreateInstance(typeof(T), someId);
this.Add(t);
}
}
A safer approach would be to further constrain your T to have a parameterless constructor, and have methods* in your base class that would load from an integer or DataReader (*or abstract in the base, implemented in the derived).
class EntityCollectionBase<T> : List<T> where T : EntityBase, new()
{
public void Load()
{
// example
int someId = 14;
T t = new T();
t.Load(someId);
this.Add(t);
}
}
Maybe this works. But I prefer factory class instead
public class EntityCollectionBase<T> : List<T> where T : EntityBase, new()
{
public EntityBase Load()
{
return new T().Create(10);
}
}
public abstract class EntityBase
{
public abstract EntityBase Create(int a);
}

Categories