我正在试图找出将ICommand
注入我的ViewModel的正确方法。
鉴于我的ViewModel看起来像这样。
public class ViewModel : IViewModel
{
ICommand LoadCommand { get; }
ICommand SaveCommand { get; }
}
我目前在构造函数
中执行此操作public ViewModel(IRepository repository, IErrorLog errorLog, IValidator validator)
{
LoadCommand = new LoadCommandImpl(repository, errorLog);
SaveCommand = new SaveCommandImpl(repository, errorLog, validator);
}
请注意,除了构造命令之外,ViewModel根本不使用这些参数。
虽然我尝试在注入的接口中包含尽可能多的逻辑,但命令中仍然存在逻辑。
这样做似乎更合适
public ViewModel(ICommand loadCommand, ICommand saveCommand)
{
LoadCommand = loadCommand;
SaveCommand = saveCommand;
LoadCommand.SetViewModel(this);
SaveCommand.SetViewModel(this);
}
但要做到这一点,我需要像这样进行Unity注册。这不是世界末日,但似乎是一种痛苦。
container.RegisterType<ICommand, LoadCommandImpl>("loadCommand");
container.RegisterType<ICommand, SaveCommandImpl>("saveCommand");
container.RegisterType<IViewModel, ViewModel>(
new InjectionConstructor(
new ResolvedParameter<ICommand>("loadCommand"),
new ResolvedParameter<ICommand>("SaveCommand")));
或者,我可以创建ILoadCommand
和ISaveCommand
接口,但这些接口将为空或可能实现ICommand
。
我不是这些解决方案的忠实粉丝。这里推荐的方法是什么?
编辑以回应blindmeis
让我们暂时假装这不是命令。
public ViewModel(IFoo foo)
{
Bar = new Bar(foo);
}
在我看来,仅仅注入IBar更合适
public ViewModel(IBar bar)
{
Bar = bar;
}
但现在我有Bar1
和Bar2
。所以我可以做到
public ViewModel(IFoo foo)
{
Bar1 = new Bar1(foo);
Bar2 = new Bar2(foo);
}
或
public ViewModel(IBar bar1, IBar bar2)
{
Bar1 = bar1;
Bar2 = bar2;
}
答案 0 :(得分:1)
这种行为不包含在Unity中,但不难改进。
var container = new UnityContainer();
container.AddNewExtension<MapParameterNamesToRegistrationNamesExtension>();
container.RegisterType<ICommand, LoadCommand>("loadCommand");
container.RegisterType<ICommand, SaveCommand>("saveCommand");
container.RegisterType<ViewModel>(new MapParameterNameToRegistrationName());
var vm = container.Resolve<ViewModel>();
Assert.IsType(typeof(LoadCommand), vm.LoadCommand);
Assert.IsType(typeof(SaveCommand), vm.SaveCommand);
public class MapParameterNamesToRegistrationNamesExtension : UnityContainerExtension
{
protected override void Initialize()
{
var strategy = new MapParameterNamesToRegistrationNamesStrategy();
this.Context.Strategies.Add(strategy, UnityBuildStage.PreCreation);
}
}
public class MapParameterNamesToRegistrationNamesStrategy : BuilderStrategy
{
public override void PreBuildUp(IBuilderContext context)
{
if (context.Policies.Get<IMapParameterNameToRegistrationNamePolicy>(context.BuildKey) == null)
{
return;
}
IPolicyList resolverPolicyDestination;
IConstructorSelectorPolicy selector = context.Policies.Get<IConstructorSelectorPolicy>(context.BuildKey, out resolverPolicyDestination);
var selectedConstructor = selector.SelectConstructor(context, resolverPolicyDestination);
if (selectedConstructor == null)
{
return;
}
var parameters = selectedConstructor.Constructor.GetParameters();
var parameterKeys = selectedConstructor.GetParameterKeys();
for (int i = 0; i < parameters.Length; i++)
{
Type parameterType = parameters[i].ParameterType;
if (parameterType.IsAbstract || parameterType.IsInterface)
{
IDependencyResolverPolicy resolverPolicy = new NamedTypeDependencyResolverPolicy(parameterType, parameters[i].Name);
context.Policies.Set<IDependencyResolverPolicy>(resolverPolicy, parameterKeys[i]);
}
}
resolverPolicyDestination.Set<IConstructorSelectorPolicy>(new SelectedConstructorCache(selectedConstructor), context.BuildKey);
}
}
public class MapParameterNameToRegistrationName : InjectionMember
{
public override void AddPolicies(Type serviceType, Type implementationType, string name, IPolicyList policies)
{
policies.Set<IMapParameterNameToRegistrationNamePolicy>(new MapParameterNameToRegistrationNamePolicy(), new NamedTypeBuildKey(implementationType, name));
}
}
public interface IMapParameterNameToRegistrationNamePolicy : IBuilderPolicy
{
}
public class MapParameterNameToRegistrationNamePolicy : IMapParameterNameToRegistrationNamePolicy
{
}
代码和测试可以在TecX project on CodePlex的源代码中找到。项目 TecX.Unity (文件夹注入)。
答案 1 :(得分:1)
为什么不创建命令Factory
public class CommandFactory (IUnityContainer container) : ICommandFactory
{
public ICommand CreateSaveCommand()
{
return container.Resolve("SaveCommand");
}
public ICommand CreateLoadCommand()
{
return container.Resolve("LoadCommand");
}
}
public ViewModel(ICommandFactory commandFactory)
{
LoadCommand = commandFactory.CreateLoadCommand();
SaveCommand = commandFactory.CreateSaveCommand();
}