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

时间:2016-02-27 19:58:55

标签: c# generics autofac open-generics generic-interface

由于通用接口,我想解决开放式通用服务。我用autofac。

每项具体服务仅适用于具体课程。

我只能使用单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);
        }
    }
}

1 个答案:

答案 0 :(得分:0)

问题在于,如果您解决dedeeb56f744e507026fef17243da41f /home/bilal/.local/lib/python2.7/site-packages 6a1d0cac3d9e6148e2208b63a33a1e6f /home/bilal/.local/lib/python2.7/site-packages/impacket 16a4fccbb3beadfdfd72691ef8f7298c /home/bilal/.local/lib/python2.7/site-packages/mechanize 211d2b55059f6b634799fdae534decd9 /usr/lib/python2.7/dist-packages be5448890caffe81686310f127d6efae /usr/lib/python2.7/dist-packages/_markerlib cec69a0830a725e10ac4e364d44add8f /usr/lib/python2.7/dist-packages/appindicator 但实现需要多个通用类似IService<T>,则Autofac无法知道其他类型(U,V)来自何处。那么你试图用汇编扫描注册它们的方式是行不通的。