Вам не нужно звонить EndInvoke
; не называть это просто означает:
- Вы не получите возвращаемое значение из метода.
- Любые исключения, возникшие во время выполнения метода, просто исчезнут.
Звучит так, будто вы хотите «запустить и забыть», поэтому самый простой способ сделать это - использовать анонимного делегата, например:
var del = new Action(foo.Bar);
del.BeginInvoke(iar =>
{
try
{
del.EndInvoke(iar);
}
catch (Exception ex)
{
// Log the message?
}
}, null);
Вот что происходит, когда вы выполняете этот код:
- Для делегата выделен новый поток (проще говоря).
- В поток дается делегат
del
и анонимный делегат (iar => ...
).
- Поток выполняет
del
.
- Когда он завершает выполнение (или возникает исключение), результат или исключение сохраняются и выполняется анонимный делегат.
- Внутри анонимного делегата, когда вызывается
EndInvoke
, результат из метода либо возвращается, либо выдается исключение (если оно произошло).
Обратите внимание, что приведенный выше пример сильно отличается от:
// This is pointless and is still, essentially, synchronous.
del.EndInvoke(del.BeginInvoke(null, null));
Редактировать: Вы всегда должны звонить End*
. Я никогда не встречал сценарий, в котором его отсутствие вызывает проблему, однако это детали реализации и основано на недокументированном поведении.
Наконец, ваше решение может привести к аварийному завершению процесса при возникновении исключения, вы можете просто передать null в качестве делегата, если вас не волнует исключение (del.BeginInvoke(myStruct, null, null);
). Так что в качестве последнего примера то, что вы ищете, вероятно:
public class A
{
// ...
void Foo(S myStruct){...}
void FooAsync(S myStruct)
{
var del = new Action<S>(Foo);
del.BeginInvoke(myStruct, SuppressException, del);
}
static void SuppressException(IAsyncResult ar)
{
try
{
((Action<S>)ar.AsyncState).EndInvoke(ar);
}
catch
{
// TODO: Log
}
}
}