在ASP.NET Core中,您可以使用Microsoft的依赖注入框架
is bind “open generics”(通用类型绑定到具体类型),如下所示:
public void ConfigureServices(IServiceCollection services) { services.AddSingleton(typeof(IRepository<>),typeof(Repository<>)) }
你也可以雇用the factory pattern to hydrate dependencies.这是一个例子:
public interface IFactory<out T> { T Provide(); } public void ConfigureServices(IServiceCollection services) { services.AddTransient(typeof(IFactory<>),typeof(Factory<>)); services.AddSingleton( typeof(IRepository<Foo>),p => p.GetrequiredService<IFactory<IRepository<Foo>>().Provide() ); }
但是,我无法弄清楚如何将这两个概念结合在一起.看起来它会以这样的方式开始,但是我需要用于合并IRepository<>实例的具体类型.
public void ConfigureServices(IServiceCollection services) { services.AddTransient(typeof(IFactory<>),typeof(Factory<>)); services.AddSingleton( typeof(IRepository<>),provider => { // Say the IServiceProvider is trying to hydrate // IRepository<Foo> when this lambda is invoked. // In that case,I need access to a System.Type // object which is IRepository<Foo>. // i.e.: repositoryType = typeof(IRepository<Foo>); // If I had that,I could snag the generic argument // from IRepository<Foo> and hydrate the factory,like so: var modelType = repositoryType.GetGenericArguments()[0]; var factoryType = typeof(IFactory<IRepository<>).MakeGenericType(modelType); var factory = (IFactory<object>)p.GetrequiredService(factoryType); return factory.Provide(); } ); }
如果我尝试使用Func< IServiceProvider,对象> functor与一个开放的通用,我得到this ArgumentException
与消息打开通用服务类型’IRepository< T>需要注册一个打开的通用实现类型.从dotnet CLI.它甚至没有到达lambda.
这种类型的绑定是否可能与Microsoft的依赖注入框架?
解决方法
net.core依赖关系不允许您在注册开放通用类型时提供工厂方法,但您可以通过提供将实现所请求的接口的类型来解决此问题,但在内部将作为工厂.伪装工厂:
services.AddSingleton(typeof(IMongoCollection<>),typeof(MongoCollectionFactory<>)); //this is the important part services.AddSingleton(typeof(IRepository<>),typeof(Repository<>)) public class Repository : IRepository { private readonly IMongoCollection _collection; public Repository(IMongoCollection collection) { _collection = collection; } // .. rest of the implementation } //and this is important as well public class MongoCollectionFactory<T> : IMongoCollection<T> { private readonly _collection; public RepositoryFactoryAdapter(IMongoDatabase database) { // do the factory work here _collection = database.GetCollection<T>(typeof(T).Name.ToLowerInvariant()) } public T Find(string id) { return collection.Find(id); } // ... etc. all the remaining members of the IMongoCollection<T>,// you can generate this easily with ReSharper,by running // delegate implementation to a new field refactoring }
当容器解析MongoCollectionFactory ti将知道T是什么类型并且将正确地创建集合.然后我们将创建的集合保存在内部,并将所有调用委托给它. (我们正在模拟这个= c.Crarp中不允许的工厂.create():))
更新:
正如Kristian Hellang所指出的,ASP.NET Logging使用了相同的模式
public class Logger<T> : ILogger<T> { private readonly ILogger _logger; public Logger(ILoggerFactory factory) { _logger = factory.CreateLogger(TypeNameHelper.GetTypeDisplayName(typeof(T))); } void ILogger.Log<TState>(...) { _logger.Log(logLevel,eventId,state,exception,formatter); } }
原创讨论区: