Как получить возвращаемое значение, когда BeginInvoke / Invoke вызывается в C # - PullRequest
38 голосов
/ 06 февраля 2010

У меня есть этот маленький метод, который должен быть потокобезопасным. Все работает, пока я не хочу, чтобы оно имело возвращаемое значение вместо void. Как получить возвращаемое значение при вызове BeginInvoke?

public static string readControlText(Control varControl) {
        if (varControl.InvokeRequired) {
            varControl.BeginInvoke(new MethodInvoker(() => readControlText(varControl)));
        } else {
            string varText = varControl.Text;
             return varText;
        }

    }

Edit: я думаю, что BeginInvoke не является обязательным в этом случае, так как мне нужно значение из GUI, прежде чем поток сможет продолжить Так что использование Invoke также хорошо. Просто не знаю, как использовать его в следующем примере, чтобы вернуть значение.

private delegate string ControlTextRead(Control varControl);
    public static string readControlText(Control varControl) {
        if (varControl.InvokeRequired) {
            varControl.Invoke(new ControlTextRead(readControlText), new object[] {varControl});
        } else {
            string varText = varControl.Text;
             return varText;
        }

    }

Но не уверен, как получить значение, используя этот код;)

Ответы [ 6 ]

58 голосов
/ 06 февраля 2010

Вам нужно вызвать Invoke (), чтобы вы могли дождаться возврата функции и получить ее возвращаемое значение. Вам также понадобится другой тип делегата. Это должно работать:

public static string readControlText(Control varControl) {
  if (varControl.InvokeRequired) {
    return (string)varControl.Invoke(
      new Func<String>(() => readControlText(varControl))
    );
  }
  else {
    string varText = varControl.Text;
    return varText;
  }
}
17 голосов
/ 06 февраля 2010

EndInvoke может использоваться для получения возвращаемого значения из вызова BeginInvoke. Например:

    public static void Main() 
    {
        // The asynchronous method puts the thread id here.
        int threadId;

        // Create an instance of the test class.
        AsyncDemo ad = new AsyncDemo();

        // Create the delegate.
        AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);

        // Initiate the asychronous call.
        IAsyncResult result = caller.BeginInvoke(3000, 
            out threadId, null, null);

        Thread.Sleep(0);
        Console.WriteLine("Main thread {0} does some work.",
            Thread.CurrentThread.ManagedThreadId);

        // Call EndInvoke to wait for the asynchronous call to complete,
        // and to retrieve the results.
        string returnValue = caller.EndInvoke(out threadId, result);

        Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",
            threadId, returnValue);
    }
}
4 голосов
/ 06 февраля 2010
public static string readControlText(Control varControl)
{
    if (varControl.InvokeRequired)
    {
        string res = "";
        var action = new Action<Control>(c => res = c.Text);
        varControl.Invoke(action, varControl);
        return res;
    }
    string varText = varControl.Text;
    return varText;
}
2 голосов
/ 06 февраля 2010

Если вы хотите получить возвращаемое значение от вашего метода, вы не должны использовать асинхронную версию метода, вы должны использовать .Invoke(...). Это синхронно, то есть он выполнит ваш делегат и не вернется, пока не завершится. В вашем примере, как сейчас, BeginInvoke отправит запрос на выполнение вашего делегата и сразу же вернется. Так что возвращать нечего.

1 голос
/ 06 февраля 2010

Это то, что вы хотели?

// begin execution asynchronously
IAsyncResult result = myObject.BeginInvoke("data.dat", null, null);

// wait for it to complete
while (result.IsCompleted == false) {
   // do some work
   Thread.Sleep(10);
   }

// get the return value
int returnValue = myObject.EndInvoke(result);
0 голосов
/ 21 января 2014
delegate string StringInvoker();
    string GetControlText()
    {
        if (control.InvokeRequired)
        {
            string controltext = (string)control.Invoke(new StringInvoker(GetControlText));
            return(controltext);
        }
        else
        {
            return(control.Text);
        }
    }

// просто и элегантно, но необходимо дождаться, пока другой поток выполнит делегат Однако, если вы не можете продолжить без результатов ...

...