Как получить возвращаемое значение, когда BeginInvoke/Invoke вызывается в С#
У меня есть этот маленький метод, который должен быть потокобезопасным. Все работает, пока я не хочу, чтобы оно возвращало значение вместо void. Как получить возвращаемое значение при вызове BeginInvoke?
public static string readControlText(Control varControl) {
if (varControl.InvokeRequired) {
varControl.BeginInvoke(new MethodInvoker(() => readControlText(varControl)));
} else {
string varText = varControl.Text;
return varText;
}
}
Изменить: я предполагаю, что BeginInvoke не является обязательным в этом случае, поскольку мне нужно значение из графического интерфейса пользователя, прежде чем поток сможет продолжить. Поэтому использование 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;
}
}
Но не уверен, как получить значение с помощью этого кода:)
Ответы
Ответ 1
Вы должны вызывать(), чтобы вы могли дождаться возвращения функции и получить ее возвращаемое значение. Вам также понадобится другой тип делегата. Это должно работать:
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;
}
}
Ответ 2
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);
}
}
Ответ 3
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
Если вы хотите получить возвращаемое значение из вашего метода, вы не должны использовать асинхронную версию метода, вы должны использовать .Invoke(...)
. Это синхронно, то есть он выполнит ваш делегат и не вернется, пока он не завершится. В вашем примере, как и сейчас, BeginInvoke отправит запрос для выполнения вашего делегата и сразу вернется. Поэтому ничего не вернуть.
Ответ 5
Что-то вроде этого, что вы хотели?
// 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);
Ответ 6
delegate string StringInvoker();
string GetControlText()
{
if (control.InvokeRequired)
{
string controltext = (string)control.Invoke(new StringInvoker(GetControlText));
return(controltext);
}
else
{
return(control.Text);
}
}
//простой и элегантный, но нужно ждать, пока другой поток выполнит делегирование; однако если вы не можете продолжить без результатов...