c# - 基于具体类型在 Unity 中注册泛型类型

标签 c# generics inversion-of-control ninject unity-container

我正在尝试模拟我可以在 Ninject 中配置的行为,但只使用 Unity。

我正在尝试使用缓存存储库模式,给定以下类和接口(interface):

public interface IRepository<T>
{
    T Get();
}

public class SqlRepository<T> : IRepository<T>
    where T : new()
{
    public T Get()
    {
        Console.WriteLine("Getting object of type '{0}'!", typeof(T).Name);
        return new T();
    }
}

public class CachedRepository<T> : IRepository<T>
    where T : class
{
    private readonly IRepository<T> repository;

    public CachedRepository(IRepository<T> repository)
    {
        this.repository = repository;
    }

    private T cachedObject;
    public T Get()
    {
        if (cachedObject == null)
        {
            cachedObject = repository.Get();
        }
        else
        {
            Console.WriteLine("Using cached repository to fetch '{0}'!", typeof(T).Name);
        }
        return cachedObject;
    }
}

基本上,只要我的应用程序使用 IRepository<T> , 它应该得到 CachedRepository<T> 的一个实例.但是在 CachedRepository<T> 里面它应该获取 SqlRepository<T> 的实际 SQL 存储库.在 Ninject 中,我使用以下方法完成了此操作:

ninjectModule.Bind(typeof(IRepository<>)).To(tyepof(SqlRepository<>)).WhenInjectedExactlyInto(tyepof(CachedRepository<>));
ninjectModule.Bind(typeof(IRepository<>)).To(tyepof(CachedRepository<>));

在 Unity 中,我如何完成同样的事情?我有一个适用于非通用存储库的版本:

UnityContainer container = new UnityContainer();
container.RegisterType<IWidgetRepository, CachedWidgetRepository>(new InjectionMember[] { new InjectionConstructor(new SqlWidgetRepository()) });

但是这种语法对通用存储库根本不起作用,因为你不能说 new SqlRepository<>没有语法错误。有什么想法吗?

最佳答案

假设您不想注册每个可能的泛型,如下所示:

container.RegisterType<IRepository<Things>, CachedRepository<Things>>(new InjectionMember[] {new InjectionConstructor(new SqlRepository<Things>())});

container.RegisterType<IRepository<OtherThings>, CachedRepository<OtherThings>>(new InjectionMember[] {new InjectionConstructor(new SqlRepository<OtherThings>())});

您可以改用自定义注入(inject)工厂,这只是“编写您自己的工厂函数”的一种奇特说法。

// We will ask Unity to make one of these, so it has to resolve IRepository<Things>
public class UsesThings
{
    public readonly IRepository<Things> ThingsRepo;

    public UsesThings(IRepository<Things> thingsRepo)
    {
        this.ThingsRepo = thingsRepo;
    }
}


class Program
{
    static void Main(string[] args)
    {
        var container = new UnityContainer();

        // Define a custom injection factory.
        // It uses reflection to create an object based on the requested generic type.
        var cachedRepositoryFactory = new InjectionFactory((ctr, type, str) =>
            {
                var genericType = type.GenericTypeArguments[0];
                var sqlRepoType = typeof (SqlRepository<>).MakeGenericType(genericType);
                var sqlRepoInstance = Activator.CreateInstance(sqlRepoType);
                var cachedRepoType = Activator.CreateInstance(type, sqlRepoInstance);
                return cachedRepoType;
            });

        // Register our fancy reflection-loving function for IRepository<>
        container.RegisterType(typeof(IRepository<>), typeof(CachedRepository<>), new InjectionMember[] { cachedRepositoryFactory });

        // Now use Unity to resolve something
        var usesThings = container.Resolve<UsesThings>();
        usesThings.ThingsRepo.Get(); // "Getting object of type 'Things'!"
        usesThings.ThingsRepo.Get(); // "Using cached repository to fetch 'Things'!"
    }
}

关于c# - 基于具体类型在 Unity 中注册泛型类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24369425/

相关文章:

c# - 转换 .resx 类以获取 ResourceSet

c# - 设置 Asp.Net Core MVC Json 选项

java - 带菱形运算符的通配符

c# - 如何重构这些泛型方法?

java - 用于泛型类型的 Jackson 反序列化器

asp.net-mvc - Structuremap 不适用于 MVC4

asp.net-mvc - Unity.MVC4惰性<T>在ASP.NET MVC应用程序中不起作用

c# - 无法在 C# 中创建连接字符串

c# - SerialPort.GetPortNames() 返回不正确的端口名称

c# - 当基类中只需要依赖时,在基类中使用属​​性注入(inject)是否合适?