如何使匿名方法接受可变数量的参数?

3

我希望能够使用变量数量的匿名方法进行内联调用(有时不带参数,有时带11个参数)。

Dictionary<string, Action> ActionDic = new Dictionary<string, Action>();
int i = 0;
ActionDic["something"] = () => { i += 1; };           // this line is ok
ActionDic["somethingArgs"] = (int n) => { n += 1; };  // but this is not
    // Delegate 'System.Action' does not take 1 arguments

所以我不能使委托接受那样的参数。我的语法有错吗,还是根本不可能?或者我必须改变匿名方法的类型来使用字典?


好的,我更改了标题,以便更清楚地表达我的意思。 - user1306322
2
无论 ActionDic 是什么,它的字符串索引器都接受 Action(或另一个没有返回类型的无参委托)。如果它是 Action<T>,你可以这样做:p => DoStuff(p) - Şafak Gür
@user1306322 请考虑阅读如何传递可选参数。虽然它与匿名方法无关,但它可能会给你一些关于如何传递可变数量的参数的线索。 - horgh
@KonstantinVasilcov 我熟悉如何使参数可选,但还是谢谢你提供的链接。 - user1306322
4个回答

4

如果你想定义一个带有1个整数参数的委托,可以使用Action<int>。例如:

Action<int> somethingArgs = (int n) => { n += 1; };

您没有展示变量ActionDic的具体内容,但如果它是一个IDictionary<string, Action>类型,那么您不能让它工作,因为Action不接受参数。
另一方面,您可以使用委托字典:
IDictionary<string, Delegate> ActionDic = ...
ActionDic["something"] = (Action)(() => { i += 1; }); 
ActionDic["somethingArgs"] = (Action<int>)((int n) => { n += 1; });

如果我可以问一下,如何使委托也能返回某些东西?(非 void) - user1306322
1
你可以使用 Func<TResult>。如果你想要它带一个参数,你可以使用 Func<TArg, TResult>。如果你想要两个参数:Func<TArg1, TArg2, TResult>。以此类推。 - Darin Dimitrov
所以我猜我不能只使用一个字典,因为这些将是不同类型的匿名方法。 - user1306322
1
当然可以使用字典。您只需要将其制作为“IDictionary<string,Delegate>”,如我的答案所示。“Delegate”是所有委托的基类。 - Darin Dimitrov

3

无法这样做。 ActionAction<T> 是不同的、不兼容的委托类型。

有几种方法可以弥补这个问题。

一种方法是将 ActionDic 设为 Dictionary<string, Action<int>>,但这可能不能满足您想使用的所有可能的委托。

另一种方法是将 ActionDic 设为类似于 Dictionary<string, Delegate> 的东西,但这样使用起来会很麻烦,因为您需要确切地知道要传递给每个函数多少个参数(以及它们的类型)。 这些信息需要在其他数据结构中存储。

还有第三种方法,即将 ActionDic 设为 Dictionary<string, Action<object[]>> 并要求委托从输入中解包其所需的任何参数。 调用方负责知道要使用哪些参数。 这将允许第二个选项的语法略微不那么笨拙,但每个委托需要更多的代码。


жҲ‘е·Із»ҸеҮҶеӨҮеҘҪдёәжӯӨеҲӣе»әдёҖдёӘеҚ•зӢ¬зҡ„委жүҳз®ЎзҗҶеҷЁзұ»пјҢдҪҶжҳҜжҲ‘д»Қ然еёҢжңӣдҪҝжҜҸдёӘ委жүҳзҡ„еЈ°жҳҺжҜ”ActionDic ["somethingArgs"] =пјҲAction <int>пјүпјҲпјҲint nпјү=> {/ * ... * /}пјү;жӣҙе®№жҳ“йҳ…иҜ»пјҢеӣ дёәеҸҜиғҪжңүеҫҲеӨҡеҸӮж•°гҖӮ - user1306322
@user1306322 我添加了第三种可能性,这可能会更容易阅读:ActionDic["somethingArgs"] = (object[] objs) => { int n = (int)objs[0]; /* ... */ }; - Mike Zboray
谢谢,现在我明白了如何在代码的一个部分提高可读性可能会导致另一个部分出问题 :) - user1306322

2
您在谈论两个不同的委托,即 ActionAction<T>。您不能将 Action<T> 赋值给 Action
Action a1 = () => { i += 1; };
Action<int> a2 = (n) => { n += 1; };

我猜你正在使用Dictionary<string,Action>,所以这个字典无法接受Action<T>类型的值。
顺便说一下,我认为第二个委托是完全没有用的,因为它增加了一个按值传递的int参数,实际上并没有做任何事情。
还要考虑阅读如何传递可选参数。虽然它与匿名方法无关,但它可能会给你一些关于如何传递可变数量的参数的线索。

0

Action是一种创建返回void且不带参数的委托的简短方式。如果您想要带参数的Action,您需要使用泛型形式:

Action<int>是一个带有一个int参数的委托

Action<string, double>带有2个参数:第一个是字符串,第二个是双精度浮点数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接