Factory Pattern with Open Generics

前端 未结 4 448
南旧
南旧 2020-12-13 18:12

In ASP.NET Core, one of the things you can do with Microsoft\'s dependency injection framework is bind \"open generics\" (generic types unbound to a concrete type) like so:<

4条回答
  •  温柔的废话
    2020-12-13 18:37

    The net.core dependency does not allow you to provide a factory method when registering an open generic type, but you can work around this by providing a type that will implement the requested interface, but internally it will act as a factory. A factory in disguise:

    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 : IMongoCollection {
        private readonly _collection;
    
        public RepositoryFactoryAdapter(IMongoDatabase database) {
            // do the factory work here
            _collection = database.GetCollection(typeof(T).Name.ToLowerInvariant())
        }
    
        public T Find(string id) 
        {
            return collection.Find(id);
        }   
        // ... etc. all the remaining members of the IMongoCollection, 
        // you can generate this easily with ReSharper, by running 
        // delegate implementation to a new field refactoring
    }
    

    When the container resolves the MongoCollectionFactory ti will know what type T is and will create the collection correctly. Then we take that created collection save it internally, and delegate all calls to it. ( We are mimicking this=factory.Create() which is not allowed in csharp. :))

    Update: As pointed out by Kristian Hellang the same pattern is used by ASP.NET Logging

    public class Logger : ILogger
    {
        private readonly ILogger _logger;
    
        public Logger(ILoggerFactory factory)
        {
            _logger = factory.CreateLogger(TypeNameHelper.GetTypeDisplayName(typeof(T)));
        }
    
        void ILogger.Log(...)
        {
            _logger.Log(logLevel, eventId, state, exception, formatter);
        }
    }
    

    https://github.com/aspnet/Logging/blob/dev/src/Microsoft.Extensions.Logging.Abstractions/LoggerOfT.cs#L29

    original discussion here:

    https://twitter.com/khellang/status/839120286222012416

提交回复
热议问题