dimanche 19 mai 2019

C#: Construct Type Constrained Half-Closed Generic Implementations of Open Generic Interface via Open Generic Method/Class

I am trying to construct instances of an open generic repository interface whereby the implementations impose more strict type constraints than the interface. Each implementation of the repository interface needs a specific implementation of the generic type to handle certain methods/operations based on the passed type's properties (not shown for the sake of brevity).

Here is a comprehensive example of the scenario:

public interface IRepository<T> where T : class
{
    //...
}

public class BaseRepository<T> : IRepository<T> where T : DbModel
{
    //...
}

public class SqlServerDbRepository<T> : BaseRepository<T> where T : SqlServerDbModel
{
    //...
}

public abstract class DbModel
{
    //...
}

// is further derived by other models
public class SqlServerDbModel : DbModel
{
    //...
}

public class User : SqlServerDbModel
{
}


// CLIENT CODE

public static IRepository<T> BuildRepository<T>()
    where T : class
{
    if (typeof(T) == typeof(SqlServerDbModel)) // "is" keyword will not work here (according to IDE, have not checked)
    {
        return new SqlServerDbRepository<T>(); // How can T be converted or accepted as an input of type "SqlServerDbModel" (the check already confirms it, so we know it should work)
    }
    else if (typeof(T) == typeof(DbModel))
    {
        return new BaseRepository<T>(); // How can T be converted or accepted as an input of type "DbModel" (the check already confirms it, so we know it should work)
    }
    //... else throw error or just return default...
}

// USAGE
public static void TestBuildRepository()
{
    var userRepository = BuildRepository<User>();
}

I tried initially running the scenario through an IOC container (Castle Windsor in case anybody is wondering) figuring it would figure out the type constraints automatically, however, this was not possible (or at least not with the way it handles open generics and dependency injection). I figured I could use a custom factory to build the interface implementations.

The problem is in the lines matching the pattern return new XYZRepository<T>(); whereby I am not sure how to get the c# compiler to take the generic type "T" passed to it, knowing it will fully satisfy the type constraint. I am sure this could be done through reflection, but I only found information on how to build methods and properties, not generic classes. How could this be achieved?

P.S.

I cannot make any changes to the interfaces, repository implementations, or models...just in case anyone was going to make that suggestion.

Please and thanks!





Aucun commentaire:

Enregistrer un commentaire