简体   繁体   中英

Dependency Injection for Two Types Generic Interface

I am using two types generic interface called IRepository<Entity, DTO> . How can I initialize in RepositoryFactory by using Dependency Injection.

Interface that I try to initialize.

public interface IRepository<Entity, DTO> where Entity : BaseEntity where DTO : BaseDTO
{
    bool Save(Entity Entity);
    bool Save(Entity Entity, out int OutID);

    bool Update(Entity Entity);
    bool Update(Entity Entity, out int OutID);

    DTO GetRecord(Entity ID);
    DTO GetRecord(Expression<Func<Entity, bool>> predicate);

    List<DTO> GetList();
    List<DTO> GetByQuery(Expression<Func<Entity, bool>> predicate);
}

BaseEntity, BaseDTO

public abstract class BaseEntity
{
    public int ID { get; protected set; }
}

public class BaseDTO
{
    public int ID { get; protected set; }
}

AdministratorRepository

public class AdministratorRepository : Repository<AdministratorEntity, AdministratorDTO>
{
    public AdministratorRepository(string ConnectionString) : base(ConnectionString)
    {

    }

    // Implemented functions for Repository base class
}

Repository base repository class

public abstract class Repository<Entity, DTO> : IRepository<Entity, DTO> 
where Entity : BaseEntity 
where DTO : BaseDTO
{
    // Implemented functions for IRepository Interface
}

RepositoryFactory

public class RepositoryFactory<Entity, DTO> where Entity : BaseEntity where DTO : BaseDTO
{
    private static string CONNECTION_STRING = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;

    public static IRepository<Entity, DTO> Create(Repositories repository)
    {
        IRepository<Entity, DTO> iRepo = null;

        switch (repository)
        {
            //  If I do this, program wants me to cast
            case Repositories.Administrator:
                //   Casting error occured in this line.
                //   AdministratorRepository derives from Repository.
                /*
                  Cannot implicitly convert type 
                 'BusinessRules.Repositories.AdministratorRepository' to 
'BusinessRules.Repositories.IRepositories.IRepository<Entity,DTO>'. 
                  An explicit conversion exists (are you missing a cast?)
                */
                iRepo = new AdministratorRepository(CONNECTION_STRING);
                break;

           // If I do this, program throws an exception
           // Exception: TypeInitializationException
           // Exception Description: The type initializer for 'BusinessRules.Repositories.RepositoryFactory`2' threw an exception.
           case Repo.Administrator:
                iRepo = (IRepository<Entity, DTO>)(new AdministratorRepository(CONNECTION_STRING));
                break;
        }

        return iRepo;
    }
}

The scenario you have mentioned is "where you are trying to assign a more derived type object than to a generic type parameter of the interface". To allow the assignment, you should define the generic interface with out parameter type. Read this article to understand variance in C#.

You can declare a generic type parameter covariant by using the out keyword.

So define the IRepository interface as

public interface IRepository<out Entity, out DTO> where Entity : BaseEntity where DTO : BaseDTO
{
    //......
}

Full Code (sample app - Check this live fiddle)

using System;

public abstract class BaseEntity
{
    public int ID { get; protected set; }
}

public class BaseDTO
{
    public int ID { get; protected set; }
}

public interface IRepository<out Entity, out DTO> where Entity : BaseEntity where DTO : BaseDTO
{
    string GetTestString();   
}

public abstract class Repository<Entity, DTO> : IRepository<Entity, DTO> 
where Entity : BaseEntity 
where DTO : BaseDTO
{

    // Implemented functions for IRepository Interface
    public Repository(string connectionString)
    {

    }

    public abstract string GetTestString();
}

public class AdministratorEntity : BaseEntity
{

}

public class AdministratorDTO : BaseDTO
{

}

public class AdministratorRepository : Repository<AdministratorEntity, AdministratorDTO>
{
    public AdministratorRepository(string ConnectionString) : base(ConnectionString)
    {

    }

    public override string GetTestString()
    {
        return "TestString";
    }

    // Implemented functions for Repository base class
}


public class Program
{
    public static void Main()
    {

        IRepository<BaseEntity, BaseDTO> repo = new AdministratorRepository("connectionString");
        Console.WriteLine(repo.GetTestString());
        Console.WriteLine("Hello World");
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM