Подтвердить что ты не робот

Как использовать .NET Action для выполнения метода с неизвестным количеством параметров?

Я хочу выполнить некоторые операции над рабочим потоком, показывая пользователю индикатор выполнения. Я создал класс

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
   }

Прежде всего, я не могу понять, что есть и как выражается лямбда-выражение - () => - и как объект Action передал делегат с неизвестным количеством параметров.

Я хотел бы использовать BackgroundWorker с моим 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 и некоторые другие темы здесь. Любая информация об этом мне поможет.

4b9b3361

Ответ 1

Я думаю, ты немного задумываешься о вещах. Итак, начните с вершины:

  • Лямбда-выражение является обозначением для ссылки на выполнение метода. Пример:

     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();
    }
    

    Все данные фиксируются при закрытии вашего метода и, таким образом, сохраняются. Поэтому, если вам удастся пройти через Action к вашему событию с помощью свойства e.Argument, все, что вам нужно будет сделать, это вызвать (e.Argument as Action)().

Ответ 2

Нельзя использовать DynamicInvoke() для этого делегата (он принимает params object[] args как аргумент)

action.DynamicInvoke(arg1, arg2, arg3 );