代码之家  ›  专栏  ›  技术社区  ›  tobeypeters

存储带有参数的操作列表,然后执行它们

  •  -1
  • tobeypeters  · 技术社区  · 6 年前

    我有一个操作枚举,我想运行:

    public enum theActions
    {
        action1,
        action2
    }
    

    我想把它们储存在字典里:

    public Dictionary<theActions, Action> _theActions { get; }
    
    _theActions = new Dictionary<theActions, Action>
    {
        [theActions.action1] = () => action1Func()
    };
    

    每一个动作我都有自己的功能:

    public void action1Func(int inParam)
    {
        //do whatever
    }
    

    稍后,我需要调用其中一个函数:

    public void execAction(int inVar, Action action) 
    { 
        //inVar isn't the parameter I want to pass to the action. It's used, for something else.
        action(); 
    }
    
    execAction(1, _theActions[theActions.action1]);
    

    我不确定,如何更改代码以使操作在任何地方都采用参数,如果我需要一个不需要参数的操作呢?我需要在那个函数中添加一个伪参数吗?

    到目前为止,我明白了:

    using System;
    using System.Collections.Generic;
    using System.Windows.Forms;
    
    namespace WindowsFormsApp1
    {
        public partial class Form1 : Form
        {
            public enum theActions
            {
                action1,
                action2
            }
    
            public Dictionary<theActions, Action<int>> _theActions { get; }
    
            public void execAction(int inVar, Action<int> action)
            {
                //inVar isn't the parameter I want to pass to the action. It's used, for something else.
    //            action();
            }
    
            public Form1()
            {
                InitializeComponent();
    
                _theActions = new Dictionary<theActions, Action<int>>
                {
                    [theActions.action1] = (Action<int>)((int x) => action1Func(x))
                };
    
            }
    
            public void action1Func(int inParam)
            {
                //do whatever
                MessageBox.Show($"Hello ... inParam : {inParam}");
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                //This works manually
                _theActions[theActions.action1].Invoke(12);
    
                //But, I want the execAction to work
                //execAction(1, _theActions[theActions.action1]);
            }
        }
    }
    

    它可以手动调用它。我只需要帮助进入execAction()并运行它。所以,关闭。

    2 回复  |  直到 6 年前
        1
  •  0
  •   nvoigt    6 年前
    public void execAction(int someInt, Action action)
    {
        action();
    
        // or: action.Invoke();
    }
    

    您应该能够在初始化中删除整个lambda,因为您已经有一个具有一个int参数的方法:

    public Form1()
    {
        InitializeComponent();
    
        _theActions = new Dictionary<theActions, Action<int>>
        {
            [theActions.action1] = action1Func
        };
    }
    

    带有特定参数的调用如下所示:

    int yourParameter = 12345;
    execAction(42, () => (_theActions[theActions.action1]).Invoke(yourParameter));
    
        2
  •  0
  •   Cosmin Sontu    6 年前

    试着放下字典,改用这个:

    public void action1Func(int p1) //action 1 has one int parameter
    {
    }
    public void action2Func() //let's consider action 2 takes no parameters
    {
    }
    public void action3Func(int p1, int p2, int p3)
    {
    }
    // Order of parameters was changed to leverage implicit null parameters for convenience
    // See invocations below
    public void execAction(theActions action, 
                           int? inVar1 = null, int? inVar2 = null, int? inVar3 = null) 
    {
        switch (action) // Based on action kind, invoke the right function.
        {               // The mapping is now coded in a switch statement 
                        // instead of a Dictionary declaration
            case theActions.action1: action1Func(inVar1.Value); break;
            case theActions.action2: action2Func(); break;
            case theActions.action3: action3Func(inVar1.Value, inVar2.Value, inVar3.Value); break;
        }
    }
    // Invocations
    execAction(theActions.action1, 1);
    execAction(theActions.action2);
    execAction(theActions.action3, 1, 3, 5);
    

    如果对执行执行正确使用隐式参数声明,则可以调用具有任意数量参数的方法。

    您可以执行参数验证(例如,在调用之前,您可以检查IvAR1.HasValue=真)。否则,如果省略了参数(NulabLe.Valp抛出无效操作异常,如果HasValue为false),代码将很快失败。

    如果多个参数增长并变得不可管理,则可以将它们放入参数包类中,并通过构造函数验证它们的初始化。

    如果定义了这些重载,则可以获得更多的安全性(编译时检查):

    public void execAction1(int p1)
        => execAction(theActions.action1, p1);
    public void execAction2()
        => execAction(theActions.action2);
    public void execAction3(int p1, int p2, int p3)
        => execAction(theActions.action3, p1, p2, p3);
    
    // Invocations will be
    execAction1(1);
    execAction2();
    execAction3(1, 3, 5);
    

    但这最后一步有点违背了目的。您可以调用原来的方法。