Question Use Multiple Type in Generic T C#

peaq 2

New member
Joined
Jun 26, 2022
Messages
1
Programming Experience
1-3
0
I have this interface base repo with genric type T:
C#:
public interface IRepositoryBase<T> where T : class
{
 void Add(T obj);
}

and this interfaces heritance from the IRepositoryBase
C#:
public interface IClass1Repository : IRepositoryBase<Class1>
{
}
public interface IClass2Repository : IRepositoryBase<Class2>
{
}

and this the class implementation of IRepositoryBase
C#:
public class RepositoryBase<T> : IRepositoryBase<T> where T : class
{
private readonly Context _context;
public RepositoryBase(Context context)
    {
        _context = context;
    }
public void Add(T obj)
    {
        _context.Set<T>().Add(obj);
    }
}

and this the implementaion of class1 & class2
C#:
public class class1Repository : RepositoryBase<Students>, IClasse1Repository
{
public class1Repository (Context context) : base(context)
    {
    }
}

C#:
public class class2Repository : RepositoryBase<Students>, IClasse2Repository
{
public class2Repository (Context context) : base(context)
    {
    }
}

& in this methode i need to return one of Repo
C#:
private IRepositoryBase<> GetRepository(string a)
{
 var scope = _serviceScopeFactory.CreateScope();
 switch (a)
    {

case "class1":
 return scope.ServiceProvider.GetService<IClass1Repository>();
case "class2":
 return scope.ServiceProvider.GetService<IClass2Repository>();
    }
return null;
}

But inside the brackets in IRepositoryBase it takes one type of class1 or class2 so in my case I need to return by params a.
How to use union or something else to set the multiple types in barckets and choose the return by conditon in params a?
 
Last edited by a moderator:

Skydiver

Staff member
Joined
Apr 6, 2019
Messages
5,698
Location
Chesapeake, VA
Programming Experience
10+
Why did you go from strongly typed in all your other code snippets to "stringly typed" in your last code snippet?

Anyway, in my view, there isn't a way to do what you want and still follow good objected oriented programming principles. I suggest doing something like this instead:
C#:
private IRepositoryBase<T> GetRepository<T>()
{
 var scope = _serviceScopeFactory.CreateScope();
 return scope.ServiceProvider
             .GetService<T>();
}
 

Skydiver

Staff member
Joined
Apr 6, 2019
Messages
5,698
Location
Chesapeake, VA
Programming Experience
10+
I do understand that doesn't really solve your problem. All it does is push the problem up one more level, and you can't effectively create a factory method that maps one type (string) to another type (class). The only way around that is to return object instead of an IRepositoryBase<T>.

The better solution is to have your IRepositoryBase to not be generic. Eg. Not have the generic type parameter T.

As a quick aside, I see that you have a Context class as a member in your implementation. By any chance are you using this with Entity Framework? If so, take time to do searches for "repository is anti-pattern" and see how it relates to using the repository pattern with Entity Framework which already implements the repository pattern for you.
 

jmcilhinney

C# Forum Moderator
Staff member
Joined
Apr 23, 2011
Messages
4,643
Location
Sydney, Australia
Programming Experience
10+
We used to implement our own unit of work and repositories in my office and we initially kept doing so when we switched to Entity Framework. We started encountering difficulties and then we realised that your EF context basically is a unit of work and each DbSet (I believe they were EntitySet in older versions but can't recall) is a repository. As suggested above, if you implement the repository pattern yourself then you're adding an extra layer for no reason and no gain but some detriment. Just have your service layer work with the EF context.
 
Top Bottom