简体   繁体   English

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

[英]Register and resolve open generic types with many generic parameters with Autofac

I would like to resolve an open generic service due to a generic interface. 由于通用接口,我想解决一个开放的通用服务。 I use autofac. 我使用autofac。

Each concrete service works only with concrete classes. 每个具体服务仅适用于具体类。

I can resolve only one service with single generic param [see SingleOpenGenericResolveTest ]. 我只能使用单个generic param来解析一项服务[请参见SingleOpenGenericResolveTest ]。 Is it possible to register & resolve many services with many T-params [see MultiOpenGenericResolveTest ]? 是否可以使用许多T-params注册和解析许多服务[请参见MultiOpenGenericResolveTest ]?

I added only one of concrete classes for IService but it possible to be many classes of T . 我仅为IService添加了一个具体的类,但可能有T许多类。 ( TRegion : Region, TRegion : BigRegion , etc...) TRegion : Region, TRegion : BigRegion等)

Here is NUnit 3 tests or you can download my solution here : https://www.dropbox.com/s/vqmdwb6hwmzgjrb/AutofacResolveTests.zip?dl=0 这是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);
        }
    }
}

问题是,如果您解析IService<T>但是实现需要多个像Service<T,U,V>这样的泛型,则Autofac无法知道其他类型(U,V)的来源...因此,您尝试向程序集扫描进行整体注册的方法将行不通。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM