如何使用现有实例选择要在IoC容器中创建的类型

nie*_*ras 6 c# structuremap ninject ioc-container autofac

这可能只是一个新手问题,但我有以下几点:

public class FooSettings {}
public class BarSettings {}
public class DohSettings {}
// There might be many more settings types...

public interface IProcessor { ... }

public class FooProcessor
    : IProcessor
{
     public FooProcessor(FooSettings) { ... }
}

public class BarProcessor
    : IProcessor
{
     public BarProcessor(BarSettings) { ... }
}

public class DohProcessor
    : IProcessor
{
     public DohProcessor(DohSettings) { ... }
}

// There might be many more processor types with matching settings...

public interface IProcessorConsumer {}

public class ProcessorConsumer 
    : IProcessorConsumer
{
     public ProcessorConsumer(IProcessor processor) { ... }
}
Run Code Online (Sandbox Code Playgroud)

FooSettings或BarSettings的实例由外部源提供,即:

object settings = GetSettings();
Run Code Online (Sandbox Code Playgroud)

现在我想基于注入现有的设置实例来解决ProcessorConsumer,例如:

container.RegisterAssemblyTypes(...); // Or similar
container.Inject(settings);
var consumer = container.Resolve<IProcessorConsumer>();
Run Code Online (Sandbox Code Playgroud)

也就是说,如果提供了FooSettings的实例,则创建FooProcessor并将其注入ProcessorConsumer,然后解析实例.

我无法在StructureMap,Ninject和Autofac中弄清楚如何做到这一点......可能是因为我是IoC容器的新手.因此,所有这些或其他容器的答案,以便他们可以比较将非常感激.

更新:我正在寻找一种可以轻松添加新设置和处理器的解决方案.此外,还有从设置类型到处理器类型的一对一映射.但是,它还允许基于其构造函数参数在给定的处理器类型中注入其他实例/服务.即某些处理器可能需要IResourceProvider服务或类似服务.这里只是一个例子.

理想情况下,我想要像

container.For<IProcessor>.InjectConstructorParameter(settings)
Run Code Online (Sandbox Code Playgroud)

或类似的.因此,指导IoC容器使用与注入的构造函数参数实例匹配的处理器类型.

jas*_*son 6

你不希望这种依赖注入.你想要一个工厂(当然,你可以用你的容器建造).工厂会知道如何采取,IProcessorSettings并返回适当的IProcessor.简而言之,您可以构建一个工厂,该工厂使用实现的对象的具体类型IProcessorSettings和容器来解析相应类型的实例.


Jos*_*gan 1

我认为您正在寻找的是ForObject()StructureMap 中的方法。它可以根据给定的对象实例关闭开放的泛型类型。您需要对设计进行的关键更改是引入泛型类型:

public interface IProcessor { }
public interface IProcessor<TSettings> : IProcessor{}
Run Code Online (Sandbox Code Playgroud)

所有重要的东西仍然在 上声明IProcessor,泛型IProcessor<TSettings>实际上只是一个标记接口。然后,每个处理器将实现通用接口,以声明它们期望的设置类型:

public class FooProcessor : IProcessor<FooSettings>
{
     public FooProcessor(FooSettings settings) {  }
}

public class BarProcessor : IProcessor<BarSettings>
{
     public BarProcessor(BarSettings settings) {  }
}

public class DohProcessor : IProcessor<DohSettings>
{
     public DohProcessor(DohSettings settings) {  }
}
Run Code Online (Sandbox Code Playgroud)

现在,给定一个设置对象的实例,您可以检索正确的IProcessor

IProcessor processor = container.ForObject(settings).
  GetClosedTypeOf(typeof(IProcessor<>)).
  As<IProcessor>();
Run Code Online (Sandbox Code Playgroud)

现在,您可以告诉 StructureMap 在解析时使用此逻辑IProcessor

var container = new Container(x =>
{
    x.Scan(scan =>
    {
        scan.TheCallingAssembly();
        scan.WithDefaultConventions();
        scan.ConnectImplementationsToTypesClosing(typeof(IProcessor<>));
    });

    x.For<IProcessor>().Use(context =>
    {
        // Get the settings object somehow - I'll assume an ISettingsSource
        var settings = context.GetInstance<ISettingsSource>().GetSettings();
        // Need access to full container, since context interface does not expose ForObject
        var me = context.GetInstance<IContainer>();
        // Get the correct IProcessor based on the settings object
        return me.ForObject(settings).
            GetClosedTypeOf(typeof (IProcessor<>)).
            As<IProcessor>();
    });

});
Run Code Online (Sandbox Code Playgroud)