c# – 具有开放泛型的工厂模式

前端之家收集整理的这篇文章主要介绍了c# – 具有开放泛型的工厂模式前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在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

猜你在找的C#相关文章