【问题标题】:Pass Method as Parameter using C# with Parameters - Using the Command Pattern使用带有参数的 C# 将方法作为参数传递 - 使用命令模式
【发布时间】:2021-10-24 22:21:36
【问题描述】:

我是传递代表的新手,想知道下面的代码是否可行?

CommandQueue.AddCommand(
    new CommandItem(
        group.MyGroupActionMovement(
            new Vector3(-1000,-1000,-1000))));

好的,详细说明一下,我将对命令模式的错误尝试进行代码转储...

所以我正在尝试创建一个命令队列。仅从移动命令开始。它需要一个vector3作为参数。其他命令将具有不同的参数,例如枚举和游戏对象。

这应该是我的命令/操作界面,但我一直在搞乱它,看看我能做什么。

public class IGroupAction: MonoBehaviour
{
    public delegate bool Del(Vector3 destination);

    public virtual bool Execute()
    {
        return true;
    }
}

这应该是命令/动作单元/项目

public class GroupActionItem
    {
     public IGroupAction MyGroupAction;

     public GroupActionItem(IGroupAction.Del action)
    {
            
    }
       
    public bool PerformAction()
    {
      return MyGroupAction.Execute();
    }
}

这是我目前完成的命令模式

public class GroupAction
{
    public List<GroupActionItem> Actions;

    public GroupAction()
    {
        Actions = new List<GroupActionItem>();
    }
        
    public void AddAction(GroupActionItem groupActionItem)
    {
        Actions.Add(groupActionItem);
    }
        
    public void ClearActions()
    {
        Actions.Clear();
    }

    public void PerformActions()
    {
        if (Actions.Count >= 1)
        {
            if(Actions[0].PerformAction())
            {
                Actions.Remove(Actions[0]);
            }
        }
    }
}

这是我执行移动命令的地方

public class GroupActionMovement : IGroupAction
{
    public override bool Execute()
    {
        return Movement();
    }

    public bool Movement(Vector3 destination)
    {
        return true;
    }
}

public class Group : MonoBehaviour
{
    public GroupActionMovement MyGroupActionMovement;
}

这是编码行为的执行。

public class Player : MonoBehaviour
{
    
    public Dictionary<Group,GroupAction> PlayerGroupsActions;
    public List<Group> Groups;
    
    void Start()
    {
        PlayerGroupsActions = new Dictionary<Group, GroupAction>();
        Groups = GetComponentsInChildren<Group>().ToList();
        foreach (Group group in Groups)
        {
            GroupAction playerGroupActions = new GroupAction();
            PlayerGroupsActions.Add(group,playerGroupActions);
        }
    }
    
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Alpha1))
        {
            //remove the foreach
            foreach (Group group in Groups)
            {
                //directly apply the group
                PlayerGroupsActions.TryGetValue(group, out GroupAction playerGroupActions);
                if (playerGroupActions != null)
                {
                    playerGroupActions.AddAction(new GroupActionItem(group.MyGroupActionMovement.Movement));
                }
            }
        }

        foreach (Group group in Groups)
        {
            PlayerGroupsActions.TryGetValue(group, out GroupAction playerFormationActions);
            if (playerFormationActions != null)
            {
                if (playerFormationActions.Actions.Count != 0)
                {
                    playerFormationActions.PerformActions();
                }
            }
        }
    }
}

如果这不是对正在发生的事情的最佳解释,或者代码转储不是解释我在做什么的最佳方式,我很抱歉。

【问题讨论】:

  • 可能与什么有关?委托人在哪里,这里的签名是什么。
  • 除非您详细解释此处涉及的所有内容,否则无法回答此问题。解释上述语句中涉及的所有类型、方法和结果。

标签: c# design-patterns


【解决方案1】:

不要将它作为方法传递,使用类似这样的东西

CommandQueue.Command += doSomething;
void doSomething()
{
//doSomething
}

因此,每当函数 CommandQueue.Command 在单独的类中运行时,它也会在主类中运行 doSomething() void

【讨论】:

    【解决方案2】:

    委托不是方法调用,而是它自己的方法,以便接收者在需要时调用它,并使用它想要的参数。

    这是一个例子:

    public delegate int MyDelegate(Vector3 vec);
    
    public class MyCallingClass
    {
        public void DoSomething(MyDelegate method)
        {
            // Do something.
    
            int result = method(new Vector3(-1000, -1000, -1000));
    
            // Do something else.
        }
    }
    
    public class MyClass
    {
        public static int MyStaticMethod(Vector3 arg)
        {
            // Do something with arg.
            return x;
        }
    
        int MyMethod(Vector3 arg)
        {
            // Do something with arg.
            return x;
        }
    
        private void DelegateWork()
        {
            MyCallingClass c = // Get an instance of MyCallingClass.
    
            c.DoSomething(this.MyMethod);
            c.DoSomething(MyClass.MyStaticMethod);
        }
    }
    

    这里有很多要理解的事情:

    1. c.DoSomething(this.MyMethod) 行,this 被捕获到您传递的委托中,这意味着当MyCallingClass.DoSomething 调用委托时,它将在MyClass 的实例上调用。 c.DoSomething(MyClass.MyStaticMethod) 行将在没有实例的情况下调用它,因为它是一个静态方法。

    2. 这是决定传递哪些参数的方法MyCallingClass.DoSomething,而不是提供委托的方法。

    3. 如果您需要调用者提供参数,而调用部分只决定何时调用而不决定传递哪些参数,那么您可以提前捕获参数,并传递不带参数的委托,如下所示。

    public delegate int MyDelegate(); // No arguments anymore.
    
    public class MyCallingClass
    {
        public void DoSomething(MyDelegate method)
        {
            // Do something.
    
            int result = method(); // Not passing arguments anymore.
    
            // Do something else.
        }
    }
    
    public class MyClass
    {
        // ...
    
        private void DelegateWork()
        {
            MyCallingClass c = // Get an instance of MyCallingClass.
    
            c.DoSomething(() => this.MyMethod(new Vector3(-1000, -1000, -1000)));
            c.DoSomething(() => MyClass.MyStaticMethod(new Vector3(-1000, -1000, -1000));
        }
    }
    

    如果您不熟悉语法() =&gt; ...,这是一个 lambda 表达式,您可以将其视为动态创建的匿名函数。它仍然尊重返回int 并且不带参数的原型。 lambda 表达式现在捕获Vector3 实例的构造,因此在调用 lambda 时将使用此值。要理解的一个非常重要的方面是 lambda 表达式中的值是在调用 lambda 时计算的,而不是在创建时计算(惰性计算)。

    1. 您不必使用特定的delegate,而是可以使用Func&lt;Vector3, int&gt;,如下所示:
    // Not actually needed.
    // public delegate int MyDelegate(Vector3 vec);
    
    public class MyCallingClass
    {
        public void DoSomething(Func<Vector3, int> method)
        {
            ...
        }
    }
    

    【讨论】:

    • 打败我。很好的答案。
    猜你喜欢
    • 2017-10-07
    • 2021-11-14
    • 2016-09-30
    • 2022-01-27
    • 2018-09-09
    • 2019-03-26
    • 2023-02-10
    • 2012-03-25
    • 2015-11-11
    相关资源
    最近更新 更多