C# 如何使用 .NET Action 执行参数数量未知的方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13260322/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use .NET Action to execute a method with unknown number of parameters?
提问by Dan Dinu
I want to execute some operations on a worker thread while displaying a progress bar to the user. I've created a class
我想在向用户显示进度条的同时在工作线程上执行一些操作。我创建了一个类
public class ProgressBar
{
public void StartAsyncTask(Action action)
{
Task t = new Task(action);
t.start();
}
}
I found out that I can send any method to the StartAsyncTaskin the following way:
我发现我可以StartAsyncTask通过以下方式向 发送任何方法:
ProgressBar pb = new ProgressBar();
pb.StartAsyncTask( () => DoSomething(15, "something"));
public void DoSomething(int i, string s)
{
//do something
}
First of all, I can't seem to understand what is and how is lambda expression - () =>- translated and how is the Actionobject passed a delegate with an unknown number of parameters.
首先,我似乎无法理解 lambda 表达式是什么以及如何() =>- 翻译以及Action对象如何传递具有未知数量参数的委托。
I would like to use a BackgroundWorkerwith my ProgressBar but in this case I would need to invoke the action. So something like this:
我想将 aBackgroundWorker与我的 ProgressBar一起使用,但在这种情况下,我需要调用该操作。所以像这样:
void m_backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
Action action = e.Argument as Action; //same action here passed through EventArgs
//but already in a worker thread so no need for the Task object
//and now i need to somehow invoke the action object but i don't know what the parameters are.
action.Invoke( ? );
}
How is it possible in the first example to execute the action without knowing the parameters in StartAsyncTask(Action action)method?
在第一个示例中如何在不知道StartAsyncTask(Action action)方法参数的情况下执行操作?
Why do I need to know the parameters when invoking the action in this case?
为什么在这种情况下调用动作时需要知道参数?
Everything about how/why/when to use "Action" is pretty unclear to me even if I read MSDN documentation and some other threads here.
Any information on this will help me.
Action即使我阅读了 MSDN 文档和这里的其他一些线程,关于如何/为什么/何时使用“ ”的所有内容对我来说也很不清楚。任何有关这方面的信息都会对我有所帮助。
采纳答案by Tejs
I think you're overthinking things a little bit. So let's start from the top:
我觉得你有点想多了。所以让我们从顶部开始:
A lambda expression is a notation to reference a method execution. Example:
x => x + 3At the most basic level, this is representing a function that takes 1 input,
x, and then returns a value equal tox + 3. So in your situation, your expression:() => DoSomething(15, "Something")Represents a method taking 0 parameters, and then invoking the method
DoSomething(15, "Something"). The compiler is behind the scenes translating that into aFuncorActiondelegate for you. So it is in effect:new Action(delegate() { DoSomething(15, "Something") });The compiler rewrite of my simple expression above would be:
new Func<int, int>(delegate(int x) { return x + 3; });Next up, if you want to invoke an action later, the syntax for doing so is fairly straightforward:
Action someMethod = new Action(() => { Console.WriteLine("hello world"); })); someMethod(); // Invokes the delegateSo if you have a given
Actioninstance, simply invoking it with the()syntax is all you need, sinceActionis a delegate that takes 0 parameters and returns nothing.A function is similarly easy:
Func<int, int> previousGuy = x => x + 3; var result = previousGuy(3); // result is 6Lastly, if you want to pass along a method to invoke, and you don't have context for the parameters at that point, you can simply wrap your call in an action and invoke that later. For example:
var myAction = new Action(() => { // Some Complex Logic DoSomething(15, "Something"); // More Complex Logic, etc }); InvokeLater(myAction); public void InvokeLater(Action action) { action(); }All of the data is captured in a closure of your method, and thus is saved. So if you can manage to pass along an
Actionto your event with thee.Argumentproperty, all you would need to do would be to call(e.Argument as Action)().
lambda 表达式是一种引用方法执行的符号。例子:
x => x + 3在最基本的层面上,这表示一个函数接受 1 个输入,
x然后返回一个等于 的值x + 3。所以在你的情况下,你的表达:() => DoSomething(15, "Something")表示一个方法取 0 个参数,然后调用该方法
DoSomething(15, "Something")。编译器在幕后为您将其翻译成Func或Action委托。所以它是有效的:new Action(delegate() { DoSomething(15, "Something") });上面我的简单表达式的编译器重写将是:
new Func<int, int>(delegate(int x) { return x + 3; });接下来,如果你想稍后调用一个动作,这样做的语法相当简单:
Action someMethod = new Action(() => { Console.WriteLine("hello world"); })); someMethod(); // Invokes the delegate因此,如果您有一个给定的
Action实例,只需使用()语法调用它就足够了,因为它Action是一个接受 0 参数且不返回任何内容的委托。一个函数同样简单:
Func<int, int> previousGuy = x => x + 3; var result = previousGuy(3); // result is 6最后,如果您想传递一个方法来调用,并且此时您没有参数的上下文,您可以简单地将您的调用包装在一个动作中,然后再调用它。例如:
var myAction = new Action(() => { // Some Complex Logic DoSomething(15, "Something"); // More Complex Logic, etc }); InvokeLater(myAction); public void InvokeLater(Action action) { action(); }所有数据都在方法的闭包中捕获,因此被保存。因此,如果您可以设法通过属性将an 传递
Action给您的事件e.Argument,那么您需要做的就是调用(e.Argument as Action)().
回答by Hulvej
Can't you use DynamicInvoke()on that delegate (it takes params object[] argsas argument)
你不能DynamicInvoke()在那个委托上使用(它params object[] args作为参数)
action.DynamicInvoke(arg1, arg2, arg3 );

