这是事情。 我用参数调用了异步方法。所以,如果我只有一个类的例子,使用这个方法它工作正常。 但是,如果我得到了我的类的两个例子,并且它们都调用了这个异步方法,但是使用不同的参数,一个结果返回得更快,并且其他类的例子的rized处理程序。
我举了一个例子:
public class ClassExample
{
public ClassExample(int someParameter)
{
GetAsyncMethodCompleted += ClassExampleGetAsyncMethodCompleted;
GetAsyncMethod(someParameter);
}
void ClassExampleGetAsyncMethodCompleted (object sender, Args e)
{
GetAsyncMethodCompleted -= ClassExampleGetAsyncMethodCompleted;
}
}
所以很明显这条线
GetAsyncMethodCompleted -= ClassExampleGetAsyncMethodCompleted;
在这种情况下,在错误的时间执行:
ClassExample(1);
ClassExample(2);
我真的明白为什么会这样。所以我需要了解如何让它以最优雅的方式运作。
答案 0 :(得分:0)
如果你可以改变实现异步方法的类,那么最优雅的方法就是不使用基于事件的异步模式。如果您无法更改类,但允许您将某些用户状态传递给异步方法,则可以使用它来确定您是否应该处理该事件,例如:
public class ClassExample
{
private object asyncCallToken = new object();
public ClassExample(int someParameter)
{
GetAsyncMethodCompleted += ClassExampleGetAsyncMethodCompleted;
GetAsyncMethod(someParameter, asyncCallToken);
}
void ClassExampleGetAsyncMethodCompleted (object sender, Args e)
{
if (e.UserState != asyncCallToken)
{
// the event was triggered by somebody's other call.
return;
}
GetAsyncMethodCompleted -= ClassExampleGetAsyncMethodCompleted;
}
}
否则,我猜,没有办法区分事件。
答案 1 :(得分:0)
如果您可以更改代码而不是使用共享事件,请使用委托参数。
public void AsyncExecute(int parameter, EventHandler completed)
{
...
}
//in your code
AsyncExecute(1, delegate (object sender, EventArgs e) { code for case 1... });
AsyncExecute(2, delegate (object sender, EventArgs e) { code for case 2... });
警告:在事件处理程序中添加和删除委托不是线程安全的。 由于事件处理程序是链接列表,并且由于它们未完全同步,因此从多个线程添加和删除事件可能会导致意外结果。
要做到这一点,我通常使用我写的两个静态函数。 它在你的情况下是没有用的,只能在某个地方保存委托调用的状态,但在其他情况下它可能很有用:
public static class SPInterlocked
{
public const int SpinWaitYieldThreshold = 10;
/// <summary>
/// Mantain a thread in wait state for a cycle.
/// spinCounter must be a reference to a local integer variable initialized to zero.
/// </summary>
public static void SpinOnce(ref int spinCounter)
{
if (spinCounter > SpinWaitYieldThreshold || ProcessorCount <= 1)
{
int num = spinCounter >= SpinWaitYieldThreshold ? spinCounter - SpinWaitYieldThreshold : spinCounter;
Thread.Sleep(num % 20 == 19 ? 1 : 0);
}
else
{
Thread.SpinWait(2 << spinCounter);
}
spinCounter = spinCounter == IntegerMaxValue ? SpinWaitYieldThreshold : spinCounter + 1;
}
/// <summary>Add an event handler as an atomic operation.</summary>
/// <returns>True if value is not null; False if null.</returns>
public static void AddHandler<EVENTHANDLER>(ref EVENTHANDLER handler, EVENTHANDLER value)
where EVENTHANDLER : class
{
Delegate dvalue = value as Delegate;
if (dvalue == null)
{
if (value == null)
throw new ArgumentNullException("value");
throw new ArgumentException("Specified value is not a delegate", "value");
}
EVENTHANDLER temp;
EVENTHANDLER current = handler;
for (int spinner = 0; ; )
{
temp = current;
EVENTHANDLER combined = Delegate.Combine(temp as Delegate, dvalue) as EVENTHANDLER;
current = Interlocked.CompareExchange(ref handler, combined, temp);
if (current == temp)
break;
SpinOnce(ref spinner);
}
while (current != temp) ;
}
/// <summary>Remove an event handler as an atomic operation.</summary>
/// <returns>True if operation was performed</returns>
public static bool RemoveHandler<EVENTHANDLER>(ref EVENTHANDLER handler, EVENTHANDLER value)
where EVENTHANDLER : class
{
Delegate dvalue = value as Delegate;
if (dvalue != null)
{
EVENTHANDLER temp;
EVENTHANDLER current = handler;
for (int spinner = 0; ; )
{
temp = current;
EVENTHANDLER combined = Delegate.Remove(temp as Delegate, dvalue) as EVENTHANDLER;
current = Interlocked.CompareExchange(ref handler, combined, temp);
if (current == temp)
break;
SpinOnce(ref spinner);
}
return true;
}
return false;
}
}
// Your code
public static class MyClass
{
private EventHandler eMyEvent;
public event EventHandler MyEvent
{
add { SPinterlocked<EventHandler>.AddHandler(ref this.eMyEvent, value); }
remove { SPinterlocked<EventHandler>.RemoveHandler(ref this.eMyEvent, value); }
}
}