C# 如果创建了一个对象,并在一个线程中分配了事件,然后从另一个线程运行,那么该事件在哪个线程上运行?
如果我在主UI线程中创建一个对象,然后从另一个线程调用该对象中的一个方法,那么引发的任何事件会在单独的线程或主UI线程中运行吗 例如:C# 如果创建了一个对象,并在一个线程中分配了事件,然后从另一个线程运行,那么该事件在哪个线程上运行?,c#,.net,events,C#,.net,Events,如果我在主UI线程中创建一个对象,然后从另一个线程调用该对象中的一个方法,那么引发的任何事件会在单独的线程或主UI线程中运行吗 例如: WebClient client = new WebClient(); client.DownloadDataCompleted += new DownloadDataCompletedEventHandler( delegate(object sender, DownloadDataCompletedEventArgs e) {
WebClient client = new WebClient();
client.DownloadDataCompleted += new DownloadDataCompletedEventHandler(
delegate(object sender, DownloadDataCompletedEventArgs e)
{
Thread.Sleep(60000);
});
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(
delegate(object sender, DoWorkEventArgs e)
{
Thread.Sleep(60000);
client.DownloadDataAsync("http://www.example.com");
});
worker.RunWorkerAsync();
将事件连接到他们自己的方法而不是代理会有什么不同吗
谢谢。事件在调用它的线程上同步引发,也就是说,事件的所有订阅服务器都在引发事件的线程中运行 您还可以通过BeginInvoke异步引发事件,在这种情况下,我相信它最终会由应用程序线程池中的线程处理 您需要保护与任何UI组件交互的任何处理程序,以防在主UI线程之外的单独线程上执行
您可以通过Control.invokererequired/Control.Invoke(…)技术来实现这一点,事件处理程序与任何其他方法一样,在调用它们的线程上运行。但是,如果处理程序是在实现
ISynchronizeInvoke
(例如winforms控件)的类上定义的,则可以在创建它的线程上调用它。下面是一个用于引发事件的扩展方法,它会自动处理此问题:
/// <summary>
/// Fires an event and catches any exceptions raised by an event handler.
/// </summary>
/// <param name="ev">The event handler to raise</param>
/// <param name="sender">The sender of the event.</param>
/// <param name="e">Event arguments for the event.</param>
/// <typeparam name="T">The type of the event args.</typeparam>
public static void Fire<T>(this EventHandler<T> ev, object sender, T e) where T : EventArgs
{
if (ev == null)
{
return;
}
foreach (Delegate del in ev.GetInvocationList())
{
try
{
ISynchronizeInvoke invoke = del.Target as ISynchronizeInvoke;
if (invoke != null && invoke.InvokeRequired)
{
invoke.Invoke(del, new[] { sender, e });
}
else
{
del.DynamicInvoke(sender, e);
}
}
catch (TargetInvocationException ex)
{
ex.InnerException.PreserveStackTrace();
throw ex.InnerException;
}
}
}
/// <summary>
/// Called on a <see cref="TargetInvocationException"/> to preserve the stack trace that generated the inner exception.
/// </summary>
/// <param name="e">The exception to preserve the stack trace of.</param>
public static void PreserveStackTrace(this Exception e)
{
var ctx = new StreamingContext(StreamingContextStates.CrossAppDomain);
var mgr = new ObjectManager(null, ctx);
var si = new SerializationInfo(e.GetType(), new FormatterConverter());
e.GetObjectData(si, ctx);
mgr.RegisterObject(e, 1, si);
mgr.DoFixups();
}
//
///激发事件并捕获事件处理程序引发的任何异常。
///
///要引发的事件处理程序
///事件的发送者。
///事件的事件参数。
///事件args的类型。
publicstaticvoidfire(此EventHandler ev,objectsender,te),其中T:EventArgs
{
如果(ev==null)
{
返回;
}
foreach(ev.GetInvocationList()中的委托del)
{
尝试
{
ISynchronizeInvoke=del.Target作为ISynchronizeInvoke;
if(invoke!=null&&invoke.invokererequired)
{
invoke.invoke(del,new[]{sender,e});
}
其他的
{
del.DynamicInvoke(发送方,e);
}
}
捕获(目标异常)
{
ex.InnerException.PreserveStackTrace();
抛出ex.InnerException;
}
}
}
///
///调用以保留生成内部异常的堆栈跟踪。
///
///保留的堆栈跟踪的异常。
公共静态跟踪(此异常为e)
{
var ctx=新StreamingContext(StreamingContextState.CrossAppDomain);
var mgr=newobjectmanager(null,ctx);
var si=new SerializationInfo(例如GetType(),new FormatterConverter());
e、 GetObjectData(si、ctx);
经理注册对象(e、1、si);
经理DoFixups();
}
编辑:保留StackTrace并不是这个问题答案的一部分,它只是我使用的解决方案的一部分。实际上,我是从另一个答案中得到这个方法的,所以,我不记得确切的答案是从哪里来的,但它的功劳确实属于其他人。对不起,我不记得是谁了