使用 Autofac 注册并解析具有许多泛型参数的开放泛型类型

本文关键字:参数 泛型 泛型类型 许多 注册 Autofac 使用 | 更新日期: 2023-09-27 18:36:41

由于通用接口,我想解析一个开放的通用服务。我使用自动法克。

每个具体服务仅适用于具体类。

我只能使用单个generic param解析一个服务 [请参阅SingleOpenGenericResolveTest]。是否可以注册和解析具有许多T-params的许多服务[见MultiOpenGenericResolveTest]?

我只为IService添加了一个具体类,但可能是许多类T.(TRegion : Region, TRegion : BigRegion等)

这是NUnit 3测试,或者您可以在此处下载我的解决方案:https://www.dropbox.com/s/vqmdwb6hwmzgjrb/AutofacResolveTests.zip?dl=0

using System;
using NUnit.Framework;
using Autofac;
using System.Reflection;
using System.Linq;
namespace AutofacResolveTests
{
    public class Address<TCity, TRegion, TSomethingElse>
        where TCity : City<TRegion>, new()
        where TRegion : Region, new()
        where TSomethingElse : SomethingElse, new()
    {
        public int Id { get; set; }
        TCity City { get; set; }
        TRegion Region { get; set; }
        TSomethingElse SomethingElse { get; set; }
    }
    public class City<TRegion>
        where TRegion : Region, new()
    {
        public int Id { get; set; }
        TRegion Region { get; set; }
    }
    public class Region
    {
        public int Id { get; set; }
    }
    public class SomethingElse
    {
        public int Id { get; set; }
    }
    public interface IService<T> where T : class
    {
        void DoSomething(T entity);
    }
    public class AddressService<TAddress, TCity, TRegion, TSomethingElse> : IService<TAddress>
        where TAddress : Address<TCity, TRegion, TSomethingElse>
        where TCity : City<TRegion>, new()
        where TRegion : Region, new()
        where TSomethingElse : SomethingElse, new()
    {
        public void DoSomething(TAddress entity)
        {
            Console.WriteLine("Hello from address service");
        }
    }
    public class CityService<TCity, TRegion> : IService<TCity>
        where TCity : City<TRegion>, new()
        where TRegion : Region, new()
    {
        public void DoSomething(TCity entity)
        {
            Console.WriteLine("Hello from city service");
        }
    }
    public class RegionService<TRegion> : IService<TRegion>
        where TRegion : Region
    {
        public void DoSomething(TRegion entity)
        {
            Console.WriteLine("Hello from region service");
        }
    }
    [TestFixture]
    public class OpenGenericResolveTests
    {
        IContainer _ioc;
        [SetUp]
        public void Setup()
        {
            var container = new ContainerBuilder();
        //manual types registration - works
        /*
        container.RegisterType(typeof(CityService<City<Region>, Region>)).As(typeof(IService<City<Region>>)).AsImplementedInterfaces();
        container.RegisterType(typeof(AddressService<
            Address<City<Region>, Region, SomethingElse>, City<Region>, Region, SomethingElse
            >))
            .As(typeof(IService<
            Address<City<Region>, Region, SomethingElse>
            >)).AsImplementedInterfaces();
        */
            var type = typeof(IService<>);
            //just get all services which implements IService
            var generics = type.Assembly.GetTypes().Where(x =>
            !x.IsInterface
            && x.Name.Contains("Service")
            && x.IsGenericType
            && x.GetInterfaces().Any(i => i.GetGenericTypeDefinition() == type)
            );
            foreach (var svcType in generics)
            {
                container.RegisterGeneric(svcType)
                .As(typeof(IService<>))
                .AsImplementedInterfaces();
            }
            _ioc = container.Build();
        }
        [Test]
        public void SingleOpenGenericResolveTest()
        {
            var reg = new Region { };
            var actual = _ioc.Resolve<IService<Region>>();
            Assert.That(actual != null);
            actual.DoSomething(reg);
        }
        [Test]
        public void MultiOpenGenericResolveTest()
        {
            //works
            var actual1 = _ioc.Resolve<IService<Region>>();
            Assert.That(actual1 != null);
            //works only with manual registration
            var actual2 = _ioc.Resolve<IService<City<Region>>>();
            Assert.That(actual2 != null);
            //works only with manual registration
            var actual3 = _ioc.Resolve<IService<Address<City<Region>,Region,SomethingElse>>>();
            Assert.That(actual3 != null);
        }
    }
}

使用 Autofac 注册并解析具有许多泛型参数的开放泛型类型

问题是,如果你解决了IService<T>但实现需要多个泛型,比如Service<T,U,V>那么 Autofac 就无法知道其他类型(U、V)来自哪里......因此,您尝试通过程序集扫描集体注册它们的方式将不起作用。