存储带有参数的操作列表并稍后执行它们
Storing a list of Actions with parameters and later executing them
我有一个枚举,我想 运行:
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]);
我不确定,如何更改我的代码以使 Action 在任何地方都接受参数,如果我需要一个不需要参数的动作怎么办?我必须在那个函数中添加一个虚拟参数吗?
我知道了,到目前为止:
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() 并 运行ning 它。所以,关闭。
尝试删除字典并改用它:
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);
如果正确使用 execAction 的隐式参数声明,则可以调用具有任意数量参数的方法。
您可以执行参数验证(例如,上面您可以在调用之前检查 inVar1.HasValue == true)否则如果您省略参数(Nullable.Value 抛出 InvalidOperationException 如果 HasValue 是假)。
如果参数数量增加并且变得难以管理,您可以将它们放入参数包中 class 并通过构造函数验证它们的初始化。
如果定义这些重载,您可以获得更高的安全性(编译时检查):
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);
但这最后一步有点违背了目的。您可以改为调用原始方法 :).
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));
我有一个枚举,我想 运行:
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]);
我不确定,如何更改我的代码以使 Action 在任何地方都接受参数,如果我需要一个不需要参数的动作怎么办?我必须在那个函数中添加一个虚拟参数吗?
我知道了,到目前为止:
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() 并 运行ning 它。所以,关闭。
尝试删除字典并改用它:
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);
如果正确使用 execAction 的隐式参数声明,则可以调用具有任意数量参数的方法。
您可以执行参数验证(例如,上面您可以在调用之前检查 inVar1.HasValue == true)否则如果您省略参数(Nullable.Value 抛出 InvalidOperationException 如果 HasValue 是假)。
如果参数数量增加并且变得难以管理,您可以将它们放入参数包中 class 并通过构造函数验证它们的初始化。
如果定义这些重载,您可以获得更高的安全性(编译时检查):
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);
但这最后一步有点违背了目的。您可以改为调用原始方法 :).
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));