基本上我正在尝试在c#中创建一个字符串到函数的字典,我已经看到过这样的实现:
Dictionary<string, Func<string, string>>
然而问题是我想要放到字典里的函数都有不同类型和数量的参数。那么我该如何创建一个能够实现这一点的字典呢?
亚当
基本上我正在尝试在c#中创建一个字符串到函数的字典,我已经看到过这样的实现:
Dictionary<string, Func<string, string>>
然而问题是我想要放到字典里的函数都有不同类型和数量的参数。那么我该如何创建一个能够实现这一点的字典呢?
亚当
您可以定义自己的委托,使用 params string[]
参数,像这样:
delegate TOut ParamsFunc<TIn, TOut>(params TIn[] args);
然后像这样声明您的字典:
Dictionary<string, ParamsFunc<string, string>> functions;
所以,您可以这样使用:
public static string Concat(string[] args)
{
return string.Concat(args);
}
var functions = new Dictionary<string, ParamsFunc<string, string>>();
functions.Add("concat", Concat);
var concat = functions["concat"];
Console.WriteLine(concat()); //Output: ""
Console.WriteLine(concat("A")); //Output: "A"
Console.WriteLine(concat("A", "B")); //Output: "AB"
Console.WriteLine(concat(new string[] { "A", "B", "C" })); //Output: "ABC"
请注意,即使您只需要一个string
参数,仍然需要使用string[]
参数声明您的方法。
另一方面,它可以使用params
样式调用(如concat()
或concat("A", "B")
)。
Dictionary<string, Delegate>
。要调用存储在Delegate
中的函数,请使用DynamicInvoke()
方法。我会选择ExpandoObject,因为它专门用来支持动态语言(例如IronPython等),让CLR支持这些语言。
static void Main()
{
dynamic expando = new ExpandoObject();
expando.Do = new Func<string>(MyFunc);
expando.Do2 = new Func<string, string>(MyFunc2);
Console.WriteLine(expando.Do());
Console.WriteLine(expando.Do2("args"));
}
static string MyFunc()
{
return "Do some awesome stuff";
}
static string MyFunc2(string arg)
{
return "Do some awesome stuff with " + arg;
}
static string Method1(string a)
{
return a;
}
static void Method2(string a, string b)
{
Console.WriteLine(a + b);
}
static string Method3(string a, string b, int x)
{
return String.Format("a:{0} b:{1} x:{2}", a, b, x);
}
static int Method4(int x)
{
return x;
}
static void Main(string[] args)
{
var methods = new Dictionary<string, Func<int, string, string, string, string>>()
{
{ "method1", (x, a, b, c) => Method1(a) },
{ "method2", (x, a, b, c) => { Method2(a, b); return ""; } },
{ "method3", (x, a, b, c) => Method3(a, b, x) },
{ "method4", (x, a, b, c) => Method4(x).ToString() },
};
foreach (var key in methods.Keys)
Console.WriteLine(key + ": " + methods[key](1, "a", "b", "c"));
Console.ReadKey();
}
正如您所看到的,为了使您的字典拥有所有可能的参数,您必须保留方法签名。这很丑陋! 但这将起作用,您不必关心哪个方法在哪个字符串后面。它们都将使用相同的参数。但是,在调用它们时,您必须非常小心,因为由于要传递的参数数量很多,您很容易在lambda表达式中调用它们时犯错误。
struct method_parameters
{
public string a;
public string b;
public int x;
}
static string Method1(method_parameters parameters)
{
return parameters.a;
}
static void Method2(method_parameters parameters)
{
Console.WriteLine(parameters.a + parameters.b);
}
static string Method3(method_parameters parameters)
{
return String.Format("a:{0} b:{1} x:{2}",
parameters.a, parameters.b, parameters.x);
}
static int Method4(method_parameters parameters)
{
return parameters.x;
}
static void Main(string[] args)
{
method_parameters parameters = new method_parameters()
{
a = "a",
b = "b",
x = 1
};
var methods = new Dictionary<string, Func<method_parameters, string>>()
{
{ "method1", Method1 },
{ "method2", (param) => { Method2(param); return ""; } },
{ "method3", Method3 },
{ "method4", (param) => Method4(param).ToString() },
};
foreach (var key in methods.Keys)
Console.WriteLine(key + ": " + methods[key](parameters));
Console.ReadKey();
}
这种方法更易于维护,因为如果您需要添加/更改参数,则不必更新每个方法和字典条目。您只需要根据所选择的参数存储方式修改您的结构/类/字典即可。但是,在调用方法之前,您需要首先更新您的结构。必要时还需要清除它!
考虑到你的使用场景是基于文本的RPG游戏,需要使用一组带参数的命令,也许你应该将所有的命令都制作成方法,这些方法都具有以下签名:
MethodName(string[] args)
使用字典查找
new Dictionary><string, Action<string[]>>
private void methodDictionary()
{
var infos = new Dictionary<string, MethodInfo>();
infos.Add("a", this.GetType().GetMethod("a"));
infos.Add("b", this.GetType().GetMethod("b"));
MethodInfo a = infos["a"];
a.Invoke(this, new[] { "a1", "b1" });
MethodInfo b = infos["b"];
b.Invoke(this, new object[] { 10, "b1", 2.056 });
}
public void a(string a, string b)
{
Console.WriteLine(a);
Console.WriteLine(b);
}
public void b(int a, string b, double c)
{
Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
}
Dictionary<string, object>
可以工作,但那甚至更糟... - James Thorpeclass FunctionDictionary
{
/// <summary>
/// Internal dictionary that will store the function delegates as Object.
/// </summary>
private Dictionary<string, Object> m_Map = new Dictionary<string, object>();
/// <summary>
/// Add method to dictionary for specified key. Encapsulated method has no parameters.
/// </summary>
public void Add<TResult>(string key, Func<TResult> function)
{
m_Map.Add(key, function);
}
/// <summary>
/// Get method for specified key. Encapsulated method has no parameters.
/// </summary>
public Func<TResult> Function<TResult>(string key)
{
return (Func<TResult>)m_Map[key];
}
/// <summary>
/// Add method to dictionary for specified key. Encapsulated method has one parameters.
/// </summary>
public void Add<T1, TResult>(string key, Func<T1, TResult> function)
{
m_Map.Add(key, function);
}
/// <summary>
/// Get method for specified key. Encapsulated method has one parameters.
/// </summary>
public Func<T, TResult> Function<T, TResult>(string key)
{
return (Func<T, TResult>)m_Map[key];
}
public void Add<T1, T2, TResult>(string key, Func<T1, T2, TResult> function)
{
m_Map.Add(key, function);
}
public void Add<T1, T2, T3, TResult>(string key, Func<T1, T2, T3, TResult> function)
{
m_Map.Add(key, function);
}
public void Add<T1, T2, T3, T4, TResult>(string key, Func<T1, T2, T3, T4, TResult> function)
{
m_Map.Add(key, function);
}
public void Add<T1, T2, T3, T4, T5, TResult>(string key, Func<T1, T2, T3, T4, T5, TResult> function)
{
m_Map.Add(key, function);
}
public void Add<T1, T2, T3, T4, T5, T6, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, TResult> function)
{
m_Map.Add(key, function);
}
public void Add<T1, T2, T3, T4, T5, T6, T7, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, TResult> function)
{
m_Map.Add(key, function);
}
public void Add<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult> function)
{
m_Map.Add(key, function);
}
public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult> function)
{
m_Map.Add(key, function);
}
public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult> function)
{
m_Map.Add(key, function);
}
public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult> function)
{
m_Map.Add(key, function);
}
public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult> function)
{
m_Map.Add(key, function);
}
public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult> function)
{
m_Map.Add(key, function);
}
public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult> function)
{
m_Map.Add(key, function);
}
public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult> function)
{
m_Map.Add(key, function);
}
public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult> function)
{
m_Map.Add(key, function);
}
public Object this[string key]
{
get
{
return m_Map[key];
}
}
public Func<T1, T2, TResult> Function<T1, T2, TResult>(string key)
{
return (Func<T1, T2, TResult>)m_Map[key];
}
public Func<T1, T2, T3, TResult> Function<T1, T2, T3, TResult>(string key)
{
return (Func<T1, T2, T3, TResult>)m_Map[key];
}
public Func<T1, T2, T3, T4, TResult> Function<T1, T2, T3, T4, TResult>(string key)
{
return (Func<T1, T2, T3, T4, TResult>)m_Map[key];
}
public Func<T1, T2, T3, T4, T5, TResult> Function<T1, T2, T3, T4, T5, TResult>(string key)
{
return (Func<T1, T2, T3, T4, T5, TResult>)m_Map[key];
}
public Func<T1, T2, T3, T4, T5, T6, TResult> Function<T1, T2, T3, T4, T5, T6, TResult>(string key)
{
return (Func<T1, T2, T3, T4, T5, T6, TResult>)m_Map[key];
}
public Func<T1, T2, T3, T4, T5, T6, T7, TResult> Function<T1, T2, T3, T4, T5, T6, T7, TResult>(string key)
{
return (Func<T1, T2, T3, T4, T5, T6, T7, TResult>)m_Map[key];
}
public Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(string key)
{
return (Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult>)m_Map[key];
}
public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>(string key)
{
return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>)m_Map[key];
}
public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult>(string key)
{
return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult>)m_Map[key];
}
public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult>(string key)
{
return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult>)m_Map[key];
}
public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult>(string key)
{
return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult>)m_Map[key];
}
public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult>(string key)
{
return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult>)m_Map[key];
}
public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult>(string key)
{
return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult>)m_Map[key];
}
public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult>(string key)
{
return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult>)m_Map[key];
}
public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult>(string key)
{
return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult>)m_Map[key];
}
}
class FunctionMapUsage
{
private FunctionDictionary functions = new FunctionDictionary();
public string FunctionA()
{
return "A";
}
public string FunctionB(int value)
{
return value.ToString();
}
public int FunctionC(string str1, string str2)
{
return str1.Length + str2.Length;
}
public void CreateFunctionMap()
{
functions.Add<string>("A", FunctionA); // Add Function A to map
functions.Add<int, string>("B", FunctionB); // Add Function B to map
functions.Add<string, string, int>("C", FunctionC); // Add Function C to map
}
public void CallFunctions()
{
var functionA = functions.Function<string>("A"); // Get Function A
var functionB = functions.Function<int, string>("B"); // Get Function B
var functionC = functions.Function<string, string, int>("C"); // Get Function C
string resultA = functionA();
string resultB = functionB(123);
int resultC = functionC("parameter 1", "parameter 2");
}
}
有几种方法可以实现这个目标,但是没有很好的答案。如果您能够做到这一点,您仍然需要更多的逻辑来调用函数,除非您的函数只有不同数量的字符串。然后每个函数都可以处理自己的参数。
话虽如此,您可以这样做:
public delegate string DelegateAction(params string[] args);
public Dictionary<string, DelegateAction> Actions = new Dictionary<string, DelegateAction>();
public void InitializeDictionary()
{
Actions.Add("walk",Move);
}
public string Move(params string[] args)
{
if (args.Length > 0)
{
if (!string.IsNullOrWhiteSpace(args[0]))
{
switch (args[0].ToLower())
{
case "forward":
return "You move forward at a leisurely pace";
case "right":
case "left":
case "backward":
throw new NotImplementedException("Still need to set these up");
default:
return "You need to specify a valid direction (forward,backward,right,left).";
}
}
}
return "You need to specify a direction.";
}
public string ProcessAction(string action, params string[] args)
{
return Actions[action.ToLower()].Invoke(args);
}
祝你好运!
public class ActionCommand
{
public ActionType ActionType { get; set; } // enum instead of string
public int Distance { get; set; }
public DirectionType DirectionType { get; set; }
// More properties as needed
}
然后,针对每个ActionType
实现一个strategy类:
public interface IActionHandlerStrategy
{
bool AppliesTo(ActionCommand actionCommand);
string Apply(ActionCommand actionCommand);
}
public class WalkActionHandlerStrategy : IActionHandlerStrategy
{
public bool AppliesTo(ActionCommand actionCommand)
{
return ActionCommand.ActionType == ActionType.Walk;
}
public ActionResult Apply(ActionCommand actionCommand)
{
// Do something here and return the result of Walk action
return new ActionResult(...); // Container for results
}
}
public class JumpActionHandlerStrategy : IActionHandlerStrategy
{
public bool AppliesTo(ActionCommand actionCommand)
{
return ActionCommand.ActionType == ActionType.Jump;
}
public ActionResult Apply(ActionCommand actionCommand)
{
// Do something here and return the result of Jump action
return new ActionResult(...); // Container for results
}
}
根据需要添加更多的策略,然后实现一个应用它们的类:
public class ActionHandler
{
// Register strategies with the handler; typically done with DI
protected IList<IActionHandlerStrategy> ActionHandlerStrategies = new List<IActionHandlerStrategy>
{
new JumpActionHandlerStrategy(),
new WalkActionHandlerStrategy(),
// More strategies here...
};
public ActionResult Handle(ActionCommand actionCommand)
{
var actionHandlerStrategy = ActionHandlerStrategies.FirstOrDefault(ahs => ahs.AppliesTo(actionCommand);
if (actionHandlerStrategy == null)
{
throw new Exception($"No strategy found for action type {actionCommand.ActionType}");
}
return actionHandlerStrategy.Apply(actionCommand);
}
}