Implementing a generic class and choosing a collection based on a type In this topic here I have aksed for help to sort out an error while creating a generic class whose method can return a different collection given a type. I received the answer and working solution but I have a feeling the problem is not sorted in proper way. That is why I came here for a review.

The reason for having a generic class is is that I use DI and pass either DbContext to collect data from a database or another Object to "collect" data from collections. The DI is done in the main Program. The interface is generic to handle DbContext and then fetching particular collection given a type: DbContext.Set&lt;&gt;(). The FetchDataFromCollection is also generic, so is FetchDataFromDatabase because this is how DbCOntext works.

Is there any other way to sort it out and for instance avoid if ... else blocks? I was thinking to make another class ModelBase, inherits from it into concrete implementations, which would return a specific collection and inject such class into FetchFromCollection but then I would have to make this decition by myself which class to inject to get proper collection in FetchFromCollection. What I would have is a method which would decide to return a particular collection given a type.

I don't know if it's possible. Below are the three program components.

IFetchData:

public interface IFetchData&lt;TEntity&gt;
{
    IEnumerable&lt;TEntity&gt; GetItems();
}


Then I have created these two classes:

FetchFromDatabase:

public class FetchFromDatabase&lt;TEntity&gt; : IFetchData&lt;TEntity&gt;
    where TEntity : class
{
    private readonly MainDBContextBase context;

    public FetchFromDatabase(MainDBContextBase context)
    {
        if (context == null)
            throw new ArgumentNullException("DB context");
        this.context = context;
    }

    public IEnumerable&lt;TEntity&gt; GetItems()
    {
        return context.Set&lt;TEntity&gt;();
    }
}


FetchFromCollection:

public class FetchFromCollection&lt;TEntity&gt; : IFetchData&lt;TEntity&gt;
    where TEntity : class
{
    // ModelBase&lt;TEntity&gt; models;

    private readonly InitializeComponents components;
    private ModelModules modules;
    private ModelSpecializations specializations;
    private ModelTeachers teachers;
    private ModelStudents students;

    public FetchFromCollection(InitializeComponents components)
    {
        if (components == null)
            throw new ArgumentNullException("Context");
        this.components = components;
    }

    public IEnumerable&lt;TEntity&gt; GetItems()
    {
        if (typeof(TEntity) == typeof(Module))
        {
            if (modules == null)
                modules = new ModelModules(components);
            return (IEnumerable&lt;TEntity&gt;)modules.Set();
        }
        if (typeof(TEntity) == typeof(Specialization))
        {
            if (specializations == null)
                specializations = new ModelSpecializations(components);
            return (IEnumerable&lt;TEntity&gt;)specializations.Set();
        }
        if (typeof(TEntity) == typeof(Module))
        {
            if (teachers == null)
                teachers = new ModelTeachers(components);
            return (IEnumerable&lt;TEntity&gt;)teachers.Set();
        }
        else
        {
            if (students == null)
                students = new ModelStudents(components);
            return (IEnumerable&lt;TEntity&gt;)students.Set();
        }
    }
}
It seems like you could just mirror the way FetchFromDatabase is implemented. First thing you will need is a something like a DbContext, but for collections. This new class should be capable of returning an IEnumerable&lt;TEntity&gt; for any TEntity defined -- just like DbContext.

public class CollectionContext
{
    private Dictionary&lt;Type, object&gt; _cache;

    public CollectionContext()
    {
        _cache = new Dictionary&lt;Type, object&gt;();
    }

    public void AddCollection&lt;TEntity&gt;(IEnumerable&lt;TEntity&gt; collection)
    {
        _cache.Add(typeof(TEntity), collection);
    }

    public IEnumerable&lt;TEntity&gt; Set&lt;TEntity&gt;()
    {
        return (IEnumerable&lt;TEntity&gt;)_cache[typeof(TEntity)];
    }
}


Now FetchFromCollection can be implemented exactly like FetchFromDatabase, with exception of the type used in the constructor. 

public class FetchFromCollection&lt;TEntity&gt; : IFetchData&lt;TEntity&gt;
where TEntity : class
{
    private readonly CollectionContext context;

    public FetchFromCollection(CollectionContext context)
    {
        if (context == null)
            throw new ArgumentNullException("Collection context");
        this.context = context;
    }

    public IEnumerable&lt;TEntity&gt; GetItems()
    {
        return context.Set&lt;TEntity&gt;();
    }
}


This is how you'd use it.

// Load up all your collections
var context = new CollectionContext();
context.AddCollection&lt;Module&gt;(new ModelModules(components).Set());
context.AddCollection&lt;Specialization&gt;(new ModelSpecializations(components).Set());
context.AddCollection&lt;Teacher&gt;(new ModelTeachers(components).Set());

// Example usage
IFetchData&lt;Module&gt; modules = new FetchFromCollection&lt;Module&gt;(context);


I think you can further improve on your design by getting rid of the generic type parameter on FetchFromDatabase and FetchFromCollection. Each of these classes is capable of pulling any TEntity out of their contexts'. By making this change you'd only need to have one instance of FetchFromDatabase and FetchFromCollection for your entire application, instead of one instance of each for every TEntity. You can just move the generic type parameter down to GetItems(). This same change would need to be made to IFetchData. Here is an example for FetchFromCollection, the same change can be made to FetchFromDatabase:

public class FetchFromCollection : IFetchData
   {
    private readonly CollectionContext context;

    public FetchFromCollection(CollectionContext context)
    {
        if (context == null)
            throw new ArgumentNullException("Collection context");
        this.context = context;
    }

    public IEnumerable&lt;TEntity&gt; GetItems&lt;TEntity&gt;()
    {
        return context.Set&lt;TEntity&gt;();
    }
}