在这个话题上有大量的讨论,但每个人似乎都错过了一个显而易见的答案。我想帮助审查这个“显而易见的”IOC容器解决方案。各种对话假设在运行时选择策略和使用IOC容器。我会继续这些假设。
我还想补充一种假设,即这不是必须选择的单一战略。相反,我可能需要检索一个对象图,该对象图具有在图的各个节点中找到的几个策略。
我将首先简要概述两种常见的解决方案,然后我将介绍“显而易见”的备选方案,我希望看到IOC容器支持。我将使用统一作为示例语法,尽管我的问题并不是专门针对团结的。
命名绑定
这种方法要求每个新策略都有手动添加的绑定:
Container.RegisterType<IDataAccess, DefaultAccessor>();
Container.RegisterType<IDataAccess, AlphaAccessor>("Alpha");
Container.RegisterType<IDataAccess, BetaAccessor>("Beta");...and然后明确请求正确的策略:
var strategy = Container.Resolve<IDataAccess>("Alpha");
抽象工厂
为了说明这种方法,假设以下类:
public class DataAccessFactory{
public IDataAccess Create(string strategy){
return //insert appropriate creation logic here.
}
public IDataAccess Create(){
return //Choose strategy through ambient context, such as thread-local-storage.
}
}
public class Consumer
{
public Consumer(DataAccessFactory datafactory)
{
//variation #1. Not sufficient to meet requirements.
var myDataStrategy = datafactory.Create("Alpha");
//variation #2. This is sufficient for requirements.
var myDataStrategy = datafactory.Create();
}
}接着IOC容器具有以下绑定:
Container.RegisterType<DataAccessFactory>();
类型切换/动态绑定
这是我想使用的方法,而不是上述两种方法。它涉及提供委托作为IOC容器绑定的一部分。大多数IOC容器都已经具备了这种能力,但是这种特定的方法有一个重要的细微差别。
语法如下所示:
Container.RegisterType(typeof(IDataAccess),
new InjectionStrategy((c) =>
{
//Access ambient context (perhaps thread-local-storage) to determine
//the type of the strategy...
Type selectedStrategy = ...;
return selectedStrategy;
})
);注意,InjectionStrategy没有返回IDataAccess的实例。相反,它返回实现IDataAccess的类型描述。接着IOC容器将执行通常的创建和这种类型的“构建”,其中可能包括正在选择的其他策略。
这与标准的类型到委托绑定形成了对比,在统一的情况下,这种绑定的编码方式如下:
Container.RegisterType(typeof(IDataAccess),
new InjectionFactory((c) =>
{
//Access ambient context (perhaps thread-local-storage) to determine
//the type of the strategy...
IDataAccess instanceOfSelectedStrategy = ...;
return instanceOfSelectedStrategy;
})
);实际上,上面的内容接近于满足总体需求,但肯定没有达到假设的统一InjectionStrategy。
关注第一个示例(它使用了一个假设的统一InjectionStrategy):
Type不可用,这意味着第一次返回该类型时性能可能会受到很小的影响。换句话说,容器必须在现场反映类型,以发现它有什么构造函数,以便它知道如何注入它。该类型的所有后续事件都应该是快速的,因为容器可以缓存它第一次发现的结果。这不是一个值得提及的“骗局”,但我正试图充分披露。
是否有一个现有的IOC容器可以以这种方式运行?有人有一个统一自定义的注入类来达到这个效果吗?
发布于 2014-03-28 06:33:40
据我所知,这个问题是关于几种候选策略之一的运行时选择或映射。
没有理由依赖DI容器来做到这一点,因为在容器无关的方式中至少有三种方法:
我个人的偏好是“部分类型名称”角色提示。
发布于 2014-03-28 15:10:09
在过去几年中,我以多种形式达到了这一要求。首先,让我们把我在你的帖子中看到的要点拉出来
假设运行时选择策略和使用IOC容器.添加一个假设,即它不是必须选择的单一策略。更确切地说,我可能需要检索一个有多种策略的对象图.不能将调用者绑定到IOC容器..。每个新策略都不需要手动添加到绑定列表中.如果国际奥委会的容器能提供更多的帮助,那就太好了。
我使用简单喷射器作为我选择的容器已经有一段时间了,这个决定的驱动因素之一是它对泛型有广泛的支持。正是通过这个特性,我们将实现您的需求。
我坚信这段代码应该代表自己,所以我会直接跳进去.
ContainerResolvedClass<T>来演示Simple找到正确的实现并成功地将它们注入构造函数中。这是类ContainerResolvedClass<T>的唯一原因。(这个类公开了为测试目的而通过result.Handlers注入的处理程序。)第一个测试要求我们为虚构类Type1获取一个实现。
[Test]
public void CompositeHandlerForType1_Resolves_WithAlphaHandler()
{
var container = this.ContainerFactory();
var result = container.GetInstance<ContainerResolvedClass<Type1>>();
var handlers = result.Handlers.Select(x => x.GetType());
Assert.That(handlers.Count(), Is.EqualTo(1));
Assert.That(handlers.Contains(typeof(AlphaHandler<Type1>)), Is.True);
}第二个测试要求我们为虚构类Type2获取一个实现。
[Test]
public void CompositeHandlerForType2_Resolves_WithAlphaHandler()
{
var container = this.ContainerFactory();
var result = container.GetInstance<ContainerResolvedClass<Type2>>();
var handlers = result.Handlers.Select(x => x.GetType());
Assert.That(handlers.Count(), Is.EqualTo(1));
Assert.That(handlers.Contains(typeof(BetaHandler<Type2>)), Is.True);
}第三个测试要求我们为虚构类Type3获得两个实现。
[Test]
public void CompositeHandlerForType3_Resolves_WithAlphaAndBetaHandlers()
{
var container = this.ContainerFactory();
var result = container.GetInstance<ContainerResolvedClass<Type3>>();
var handlers = result.Handlers.Select(x => x.GetType());
Assert.That(handlers.Count(), Is.EqualTo(2));
Assert.That(handlers.Contains(typeof(AlphaHandler<Type3>)), Is.True);
Assert.That(handlers.Contains(typeof(BetaHandler<Type3>)), Is.True);
}这些测试似乎满足了您的要求,最好的是解决方案中没有任何容器受到损害。
诀窍是使用参数对象和标记接口的组合。参数对象包含行为的数据(即IHandler),标记接口控制哪些行为作用于哪个参数对象。
下面是标记接口和参数对象--您将注意到,Type3被标记为两个标记接口:
private interface IAlpha { }
private interface IBeta { }
private class Type1 : IAlpha { }
private class Type2 : IBeta { }
private class Type3 : IAlpha, IBeta { }以下是行为(IHandler<T>):
private interface IHandler<T> { }
private class AlphaHandler<TAlpha> : IHandler<TAlpha> where TAlpha : IAlpha { }
private class BetaHandler<TBeta> : IHandler<TBeta> where TBeta : IBeta { }这是查找开放泛型的所有实现的唯一方法:
public IEnumerable<Type> GetLoadedOpenGenericImplementations(Type type)
{
var types =
from assembly in AppDomain.CurrentDomain.GetAssemblies()
from t in assembly.GetTypes()
where !t.IsAbstract
from i in t.GetInterfaces()
where i.IsGenericType
where i.GetGenericTypeDefinition() == type
select t;
return types;
}这是为我们的测试配置容器的代码:
private Container ContainerFactory()
{
var container = new Container();
var types = this.GetLoadedOpenGenericImplementations(typeof(IHandler<>));
container.RegisterAllOpenGeneric(typeof(IHandler<>), types);
container.RegisterOpenGeneric(
typeof(ContainerResolvedClass<>),
typeof(ContainerResolvedClass<>));
return container;
}最后,测试类ContainerResolvedClass<>
private class ContainerResolvedClass<T>
{
public readonly IEnumerable<IHandler<T>> Handlers;
public ContainerResolvedClass(IEnumerable<IHandler<T>> handlers)
{
this.Handlers = handlers;
}
}我意识到这篇文章很长,但我希望它能清楚地展示出解决你的问题的可能方法。
发布于 2016-06-17 12:47:54
这是一个迟来的反应,但也许它会帮助其他人。
我有个很简单的方法。我只需创建一个不直接依赖于统一的StrategyResolver。
public class StrategyResolver : IStrategyResolver
{
private IUnityContainer container;
public StrategyResolver(IUnityContainer unityContainer)
{
this.container = unityContainer;
}
public T Resolve<T>(string namedStrategy)
{
return this.container.Resolve<T>(namedStrategy);
}
}用法:
public class SomeClass: ISomeInterface
{
private IStrategyResolver strategyResolver;
public SomeClass(IStrategyResolver stratResolver)
{
this.strategyResolver = stratResolver;
}
public void Process(SomeDto dto)
{
IActionHandler actionHanlder = this.strategyResolver.Resolve<IActionHandler>(dto.SomeProperty);
actionHanlder.Handle(dto);
}
}注册:
container.RegisterType<IActionHandler, ActionOne>("One");
container.RegisterType<IActionHandler, ActionTwo>("Two");
container.RegisterType<IStrategyResolver, StrategyResolver>();
container.RegisterType<ISomeInterface, SomeClass>();现在,这方面的好处是,我以后在添加新策略时再也不用碰StrategyResolver了。
这很简单。非常干净,我把对团结的依赖性保持在最低限度。只有当我决定改变集装箱技术时,我才会接触到StrategyResolver,这是不太可能发生的。
希望这能有所帮助!
https://stackoverflow.com/questions/22701412
复制相似问题