2

ICommandViewModel にを注入する正しい方法を理解しようとしています。

私の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

私はこれらのソリューションの大ファンではありません。ここで推奨されるアプローチは何ですか?

ブラインドメイスに応じて編集する

これがコマンド以外のものであると少し考えてみましょう。

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;
}
4

2 に答える 2

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
{
}

コードとテストは、CodePlexのTecXプロジェクトのソースコードにあります。Project TecX.Unity(フォルダーインジェクション)。

于 2012-07-20T06:56:08.307 に答える
1

コマンドファクトリを作成しないのはなぜですか

 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();         
}
于 2012-07-20T08:53:39.653 に答える