Resolving IEnumerable of generic interfaces from Autofac container

北战南征 提交于 2020-04-11 06:31:47

问题


I'm not sure if this is possible, I've seen some other posts asking similar question but none have a satisfactory answer.

What I want to do is resolve a collection of interfaces with differing generic types from Autofac. So constructor of class would look something like this:

public class SomeClass<T> where T : class
{
    private readonly IEnumerable<ITestInterface<T>> _testInterfaces;

    public SomeClass(IEnumerable<ITestInterface<T>> testInterfaces)
    {
        _testInterfaces = testInterfaces;
    }
}

Ideally, I'd just like to be able to register each instance individually like so:

builder
    .RegisterType<ImplementationA>()
    .As<ITestInterface<A>>();

builder
    .RegisterType<ImplementationB>()
    .As<ITestInterface<B>>();

I've tried various combinations of RegisterGeneric etc but the Enumerable just keeps coming through empty.

Any help would be appreciated.


回答1:


I was able to resolve this after playing with inheritance & generic constraints. The solution I ended up with looks like this:

Base classes / interfaces:

public abstract class BaseClass
{
    public abstract string IAM { get; }
}

public interface ITestInterface<out T> where T : BaseClass
{
    T GetSomething();
}

Implemented classes:

public class A : BaseClass
{
    public override string IAM => "I AM TYPE A";
}

public class AInterface : ITestInterface<A>
{
    public A GetSomething()
    {
        return new A();
    }
}

public class B : BaseClass
{
    public override string IAM => "I AM TYPE B";
}

public class BInterface : ITestInterface<B>
{
    public B GetSomething()
    {
        return new B();
    }
}

Class we want to resolve:

public interface ISomeClass
{
    void DoSomething();
}

public class SomeClass<T> : ISomeClass where T : BaseClass
{
    private readonly IEnumerable<ITestInterface<T>> _testInterfaces;

    public SomeClass(IEnumerable<ITestInterface<T>> testInterfaces)
    {
        _testInterfaces = testInterfaces;
    }

    public void DoSomething()
    {
        foreach (var t in _testInterfaces)
        {
            var something = t.GetSomething();

            Console.WriteLine(something.IAM);
        }
    }
}

And finally, Autofac configuration:

var builder = new ContainerBuilder();

builder
    .RegisterType<SomeClass<BaseClass>>()
    .AsSelf();

builder
    .RegisterType<AInterface>()
    .As<ITestInterface<BaseClass>>();

builder
    .RegisterType<BInterface>()
    .As<ITestInterface<BaseClass>>();

builder
    .RegisterType<SomeClass<BaseClass>>()
    .As<ISomeClass>();

var container = builder.Build();

var x = container.Resolve<ISomeClass>();

x.DoSomething();

Outputs:

I AM TYPE A

I AM TYPE B

Hope this helps someone in the future.




回答2:


RegisterGeneric should work fine :

builder.RegisterType<TestImplementationA>()
        .As<ITestInterface<A>>();
builder.RegisterType<TestImplementationB>()
        .As<ITestInterface<B>>();
builder.RegisterGeneric(typeof(SomeClass<>))
       .As(typeof(ISomeClass<>));

or

builder.RegisterType<TestImplementationA>()
        .As<ITestInterface<A>>();
builder.RegisterType<TestImplementationB>()
        .As<ITestInterface<B>>();
builder.RegisterGeneric(typeof(SomeClass<>))
       .AsSelf();

You will find below a working sample :

public interface ISomeClass<T> where T : class
{
    Int32 Count { get; }
}
public class SomeClass<T> : ISomeClass<T> where T : class
{
    private readonly IEnumerable<ITestInterface<T>> _testInterfaces;

    public SomeClass(IEnumerable<ITestInterface<T>> testInterfaces)
    {
        _testInterfaces = testInterfaces;
    }

    public Int32 Count
    {
        get
        {
            return this._testInterfaces.Count();
        }
    }
}

public interface ITestInterface {}
public interface ITestInterface<T> : ITestInterface { }
public class A { }
public class B { }
public class TestImplementationA : ITestInterface<A> { }
public class TestImplementationB : ITestInterface<B> { }

class Program
{
    static void Main(string[] args)
    {
        ContainerBuilder builder = new ContainerBuilder();
        builder.RegisterType<TestImplementationA>()
               .As<ITestInterface<A>>()
               .As<ITestInterface>();

        builder.RegisterType<TestImplementationB>()
               .As<ITestInterface<B>>()
               .As<ITestInterface>();

        builder.RegisterGeneric(typeof(SomeClass<>))
               .As(typeof(ISomeClass<>));

        IContainer container = builder.Build();

        var x = container.Resolve<ISomeClass<A>>();

        Console.WriteLine(x.Count);

        var z = container.Resolve<IEnumerable<ITestInterface>>();
    }
}


来源:https://stackoverflow.com/questions/37801361/resolving-ienumerable-of-generic-interfaces-from-autofac-container

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!