C# 命令模式:如何将参数传递给命令?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/104918/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 14:10:42  来源:igfitidea点击:

Command Pattern : How to pass parameters to a command?

提问by Romain Verdier

My question is related to the command pattern, where we have the following abstraction (C# code) :

我的问题与命令模式有关,我们有以下抽象(C# 代码):

public interface ICommand
{
    void Execute();
}

Let's take a simple concrete command, which aims to delete an entity from our application. A Personinstance, for example.

让我们采用一个简单的具体命令,该命令旨在从我们的应用程序中删除一个实体。Person例如,一个实例。

I'll have a DeletePersonCommand, which implements ICommand. This command needs the Personto delete as a parameter, in order to delete it when Executemethod is called.

我会有一个DeletePersonCommand,它实现ICommand. 该命令需要Person删除作为参数,以便在Execute调用方法时删除它。

What is the best way to manage parametrized commands ? How to pass parameters to commands, before executing them ?

管理参数化命令的最佳方法是什么?如何在执行命令之前将参数传递给命令?

采纳答案by Blair Conrad

You'll need to associate the parameters with the command object, either by constructor or setter injection (or equivalent). Perhaps something like this:

您需要通过构造函数或 setter 注入(或等效方法)将参数与命令对象相关联。也许是这样的:

public class DeletePersonCommand: ICommand
{
     private Person personToDelete;
     public DeletePersonCommand(Person personToDelete)
     {
         this.personToDelete = personToDelete;
     }

     public void Execute()
     {
        doSomethingWith(personToDelete);
     }
}

回答by Frank Krueger

In the constructor and stored as fields.

在构造函数中并存储为字段。

You will also want to eventually make your ICommands serializable for the undo stack or file persistence.

您还需要最终使您的 ICommand 可序列化以用于撤消堆栈或文件持久性。

回答by Patrick Desjardins

DeletePersonCommand can have parameter in its constructor or methods . DeletePersonCommand will have the Execute() and in the execute can check attribute that will be passed by Getter/Setter previously the call of the Execute().

DeletePersonCommand 可以在其构造函数或方法中有参数。DeletePersonCommand 将具有 Execute() 并且在 execute 中可以检查将由 Getter/Setter 先前调用的 Execute() 传递的属性。

回答by Matt Dillard

I would add any necessary arguments to the constructor of DeletePersonCommand. Then, when Execute()is called, those parameters passed into the object at construction time are used.

我会向DeletePersonCommand. 然后,当Execute()被调用时,使用那些在构造时传递给对象的参数。

回答by Joel Martinez

Have "Person" implement some sort of IDeletable interface, then make the command take whatever base class or interface your entities use. That way, you can make a DeleteCommand, which tries to cast the entity to an IDeletable, and if that works, call .Delete

让“Person”实现某种 IDeletable 接口,然后使命令采用您的实体使用的任何基类或接口。这样,您可以创建一个 DeleteCommand,它会尝试将实体转换为 IDeletable,如果可行,请调用 .Delete

public class DeleteCommand : ICommand
{
   public void Execute(Entity entity)
   {
      IDeletable del = entity as IDeletable;
      if (del != null) del.Delete();
   }
}

回答by Juanma

There are some options:

有一些选择:

You could pass parameters by properties or constructor.

您可以通过属性或构造函数传递参数。

Other option could be:

其他选择可能是:

interface ICommand<T>
{
    void Execute(T args);
}

And encapsulate all command parameters in a value object.

并将所有命令参数封装在一个值对象中。

回答by jop

Pass the person when you create the command object:

创建命令对象时传递人:

ICommand command = new DeletePersonCommand(person);

so that when you execute the command, it already knows everything that it needs to know.

这样当你执行命令时,它已经知道它需要知道的一切。

class DeletePersonCommand : ICommand
{
   private Person person;
   public DeletePersonCommand(Person person)
   {
      this.person = person;
   }

   public void Execute()
   {
      RealDelete(person);
   }
}

回答by user12786

In this case, what we've done with our Command objects is to create a Context object which is essentially a map. The map contains name value pairs where the keys are constants and the values are parameters that are used by the Command implementations. Especially useful if you have a Chain of Commands where later commands depend on context changes from earlier commands.

在这种情况下,我们对 Command 对象所做的是创建一个本质上是地图的 Context 对象。该映射包含名称值对,其中键是常量,值是 Command 实现使用的参数。如果您有一个命令链,其中后面的命令依赖于较早命令的上下文更改,则特别有用。

So the actual method becomes

所以实际的方法变成

void execute(Context ctx);

回答by TheZenker

Based on the pattern in C#/WPF the ICommand Interface (System.Windows.Input.ICommand) is defined to take an object as a parameter on the Execute, as well as the CanExecute method.

基于 C#/WPF 中的模式,ICommand 接口 (System.Windows.Input.ICommand) 被定义为将对象作为 Execute 和 CanExecute 方法的参数。

interface ICommand
            {
                bool CanExecute(object parameter);
                void Execute(object parameter);
            }

This allows you to define your command as a static public field which is an instance of your custom command object that implements ICommand.

这允许您将命令定义为静态公共字段,它是实现 ICommand 的自定义命令对象的实例。

public static ICommand DeleteCommand = new DeleteCommandInstance();

In this way the relevant object, in your case a person, is passed in when execute is called. The Execute method can then cast the object and call the Delete() method.

通过这种方式,在调用 execute 时传入相关对象,在您的情况下是一个人。然后 Execute 方法可以转换对象并调用 Delete() 方法。

public void Execute(object parameter)
            {
                person target = (person)parameter;
                target.Delete();
            } 

回答by David Robbins

You should create a CommandArgs object to contain the parameters you want to use. Inject the CommandArgs object using the constructor of the Command object.

您应该创建一个 CommandArgs 对象来包含要使用的参数。使用 Command 对象的构造函数注入 CommandArgs 对象。