在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);
}
}
https://github.com/aspnet/Logging/blob/dev/src/Microsoft.Extensions.Logging.Abstractions/LoggerOfT.cs#L29
原创讨论区:
https://twitter.com/khellang/status/839120286222012416