我有一个事件及其方法声明如下,它是一个Windows窗体登录控件的身份验证事件:
public event EventHandler<AuthenticateEventArgs> Authenticate;
protected void OnAuthenticate(AuthenticateEventArgs e)
{
EventHandler<AuthenticateEventArgs> handler = Authenticate;
if (handler != null)
{
handler(this, e);
}
if (e.Authenticated)
{
OnLoggedIn(new EventArgs());
}
else
{
OnLoggedError(new EventArgs());
}
}
点击按钮会引发事件,现在假设在其他项目中有此事件的订阅者,如下所示:
this.loginControl1.Authenticate += loginControl1_Authenticate;
this.loginControl1.Authenticate += delegate(object o, AuthenticateEventArgs ea)
{
System.Threading.Thread.Sleep(2000);
ea.Authenticated = false;
};
this.loginControl1.Authenticate += delegate(object o, AuthenticateEventArgs ea)
{
System.Threading.Thread.Sleep(2000);
ea.Authenticated = true;
};
this.loginControl1.Authenticate += delegate(object o, AuthenticateEventArgs ea)
{
System.Threading.Thread.Sleep(2000);
ea.Authenticated = false;
};
System.Threading.Thread.Sleep(2000);
只是需要一些时间的某个过程的模拟。问题是最后一个订户在OnAuthenticate
方法中执行If条件并引发另一个事件,而订阅者之前则没有。代码适用于一个用户。在这种情况下问题在哪里?
答案 0 :(得分:1)
由于您希望异步执行身份验证方法,因此可以像这样工作。
创建一个返回bool
public delegate bool Authenticate(object sender, AuthenticateEventArgs e);
Authenticate authHandler;
您可能会也可能不会使用这些参数,但您可以稍后使用或删除它。
创建您的身份验证方法
bool AuthenticationMethod1(object o, AuthenticateEventArgs ea)
{
System.Threading.Thread.Sleep(2000); //Simulate some long running task.
return false; //Return true or false based on authentication failed or succeeded.
}
bool AuthenticationMethod2(object o, AuthenticateEventArgs ea)
{
System.Threading.Thread.Sleep(2000); //Simulate some long running task.
return true; //Return true or false based on authentication failed or succeeded.
}
bool AuthenticationMethod3(object o, AuthenticateEventArgs ea)
{
System.Threading.Thread.Sleep(2000); //Simulate some long running task.
return false; //Return true or false based on authentication failed or succeeded.
}
连接处理程序
authHandler += AuthenticationMethod1;
authHandler += AuthenticationMethod2;
authHandler += AuthenticationMethod3;
现在执行
if (authHandler != null)
{
foreach (Authenticate handler in authHandler.GetInvocationList())
{
handler.BeginInvoke(this, e as AuthenticateEventArgs, new AsyncCallback(Callback), handler);
}
}
上一篇:您是否回调定义了
void Callback(IAsyncResult ar)
{
Authenticate d = (Authenticate)ar.AsyncState;
if (d.EndInvoke(ar))
{
OnLoggedIn(new EventArgs());
}
else
{
OnLoggedError(new EventArgs());
}
}
答案 1 :(得分:0)
这是众所周知的行为,事件按订阅顺序执行,因此最后订阅的订阅者将覆盖所有先前的值。您可以看到最后一个订阅者的更新(在这种情况下为false)。
您可以通过检查已经过身份验证并跳过处理来解决此问题。
this.loginControl1.Authenticate += delegate(object o, AuthenticateEventArgs ea)
{
if(ea.Authenticated)
{
return;
}
System.Threading.Thread.Sleep(2000);
ea.Authenticated = false;
};
this.loginControl1.Authenticate += delegate(object o, AuthenticateEventArgs ea)
{
if(ea.Authenticated)
{
return;
}
System.Threading.Thread.Sleep(2000);
ea.Authenticated = true;
};
this.loginControl1.Authenticate += delegate(object o, AuthenticateEventArgs ea)
{
if(ea.Authenticated)
{
return;
}
System.Threading.Thread.Sleep(2000);
ea.Authenticated = false;
};
原因是因为您看到Authenticated
false始终为handler(this, e);
,只有在调用所有已订阅的方法后才会返回。因此,您的上一个订阅者将Authenticated
设置为false,因此只有在if (e.Authenticated)
执行时才会看到错误。
答案 2 :(得分:0)
通过以下代码删除事件:
this.loginControl1.Authenticate -= loginControl1_Authenticate;
答案 3 :(得分:0)
问题是所有事件订阅者将在与触发它们的函数相同的线程上执行,以便执行到达时
handler(this, e);
执行将移至第一个订户代码
System.Threading.Thread.Sleep(2000);
ea.Authenticated = false;
然后执行转到第二个订阅者。最后,它将执行最后一个订户代码,然后执行回到调用函数
protected void OnAuthenticate(AuthenticateEventArgs e)
并且执行从事件触发器行继续到第二个if语句,并且此时ea.Authenticated的值为false,因为上一个订阅者设置它。
如果您想在不同的帖子上提出每个事件,请检查Trigger events on separated threads