web-dev-qa-db-fra.com

Comment obtenir une valeur de retour lorsque BeginInvoke/Invoke est appelé en C #

J'ai cette petite méthode qui est censée être thread-safe. Tout fonctionne jusqu'à ce que je veuille qu'il ait une valeur de retour au lieu de vide. Comment puis-je obtenir la valeur de retour lorsque BeginInvoke est appelé? 

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

    }

Edit: J'imagine qu'avoir BeginInvoke n'est pas nessecary dans ce cas car j'ai besoin de la valeur de l'interface graphique avant que le thread puisse continuer. Donc, utiliser Invoke est également utile. Juste aucune idée de comment l'utiliser dans l'exemple suivant pour renvoyer une valeur. 

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

    }

Mais je ne sais pas comment obtenir de la valeur en utilisant ce code non plus;)

36
MadBoy

Vous devez invoke () pour pouvoir attendre que la fonction retourne et obtenir sa valeur de retour. Vous aurez également besoin d'un autre type de délégué. Cela devrait fonctionner:

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;
  }
}
56
Hans Passant

EndInvoke peut être utilisé pour obtenir une valeur de retour à partir d'un appel BeginInvoke. Par exemple:

    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);
    }
}
17
Justin Ethier
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;
}
4
Sergey Teplyakov

Si vous voulez une valeur de retour de votre méthode, vous ne devriez pas utiliser la version async de la méthode, vous devriez utiliser .Invoke(...). Ce qui est synchrone, c’est-à-dire qu’il exécutera votre délégué et ne reviendra que s’il est terminé. Dans votre exemple actuel, BeginInvoke enverra la demande d'exécution du délégué et reviendra immédiatement. Donc, il n'y a rien à revenir.

2
THX-1138

Est-ce que quelque chose comme ce que tu voulais?

// 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);
1
Randy Minder
delegate string StringInvoker();
    string GetControlText()
    {
        if (control.InvokeRequired)
        {
            string controltext = (string)control.Invoke(new StringInvoker(GetControlText));
            return(controltext);
        }
        else
        {
            return(control.Text);
        }
    }

// simple & élégant mais il faut attendre qu'un autre thread exécute delegate; Cependant, si vous ne pouvez pas continuer sans les résultats ...

0
Pablo