24

我想在向用户显示进度条的同时在工作线程上执行一些操作。我创建了一个类

public class ProgressBar
{
   public void StartAsyncTask(Action action)
   {
      Task t = new Task(action);
      t.start();
   }
}

我发现我可以StartAsyncTask通过以下方式将任何方法发送到:

  ProgressBar pb = new ProgressBar();
  pb.StartAsyncTask( () => DoSomething(15, "something"));

  public void DoSomething(int i, string s)
   {
      //do something
   }

首先,我似乎无法理解 lambda 表达式是什么以及如何() =>翻译 - 以及Action对象如何传递具有未知数量参数的委托。

我想将 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( ? ); 
}

在第一个示例中,如何在不知道StartAsyncTask(Action action)方法中的参数的情况下执行操作?

为什么在这种情况下调用动作时需要知道参数?

Action即使我在这里阅读了 MSDN 文档和其他一些线程,关于如何/为什么/何时使用 " " 的一切对我来说都不清楚。这方面的任何信息都会对我有所帮助。

4

2 回答 2

55

我觉得你有点想太多了。所以让我们从顶部开始:

  1. lambda 表达式是引用方法执行的符号。例子:

     x => x + 3
    

    在最基本的层面上,这表示一个函数,它接受 1 个输入 ,x然后返回一个等于 的值x + 3。所以在你的情况下,你的表达:

    () => DoSomething(15, "Something")
    

    表示采用 0 个参数的方法,然后调用该方法DoSomething(15, "Something")。编译器在幕后为您将其转换为 aFuncAction委托。所以它是有效的:

    new Action(delegate()
    {
        DoSomething(15, "Something")
    }); 
    

    我上面的简单表达式的编译器重写将是:

    new Func<int, int>(delegate(int x)
    {
        return x + 3;
    });
    
  2. 接下来,如果你想稍后调用一个动作,这样做的语法相当简单:

    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
    
  3. 最后,如果您想传递要调用的方法,并且此时没有参数的上下文,您可以简单地将调用包装在一个操作中,然后再调用它。例如:

    var myAction = new Action(() =>
         {
              // Some Complex Logic
              DoSomething(15, "Something");
              // More Complex Logic, etc
         });
    
    InvokeLater(myAction);
    
    public void InvokeLater(Action action)
    {
          action();
    }
    

    所有数据都在您的方法的闭包中捕获,因此被保存。因此,如果您可以设法通过Action该属性将 an 传递给您的事件e.Argument,那么您需要做的就是调用(e.Argument as Action)().

于 2012-11-06T22:42:20.503 回答
2

你不能DynamicInvoke()在那个委托上使用(它params object[] args作为参数)

action.DynamicInvoke(arg1, arg2, arg3 );
于 2016-09-01T12:01:10.233 回答