【发布时间】:2010-11-26 07:24:44
【问题描述】:
我遇到了this message board post 中描述的问题。
我有一个托管在它自己的 AppDomain 中的对象。
public class MyObject : MarshalByRefObject
{
public event EventHandler TheEvent;
...
...
}
我想为该事件添加一个处理程序。处理程序将在不同的 AppDomain 中运行。我的理解是,这一切都很好,事件通过 .NET Remoting 神奇地跨越该边界传递。
但是,当我这样做时:
// instance is an instance of an object that runs in a separate AppDomain
instance.TheEvent += this.Handler ;
...它编译正常,但在运行时失败:
System.Runtime.Remoting.RemotingException:
Remoting cannot find field 'TheEvent' on type 'MyObject'.
为什么?
编辑:演示问题的工作应用的源代码:
// EventAcrossAppDomain.cs
// ------------------------------------------------------------------
//
// demonstrate an exception that occurs when trying to use events across AppDomains.
//
// The exception is:
// System.Runtime.Remoting.RemotingException:
// Remoting cannot find field 'TimerExpired' on type 'Cheeso.Tests.EventAcrossAppDomain.MyObject'.
//
// compile with:
// c:\.net3.5\csc.exe /t:exe /debug:full /out:EventAcrossAppDomain.exe EventAcrossAppDomain.cs
//
using System;
using System.Threading;
using System.Reflection;
namespace Cheeso.Tests.EventAcrossAppDomain
{
public class MyObject : MarshalByRefObject
{
public event EventHandler TimerExpired;
public EventHandler TimerExpired2;
public MyObject() { }
public void Go(int seconds)
{
_timeToSleep = seconds;
ThreadPool.QueueUserWorkItem(Delay);
}
private void Delay(Object stateInfo)
{
System.Threading.Thread.Sleep(_timeToSleep * 1000);
OnExpiration();
}
private void OnExpiration()
{
Console.WriteLine("OnExpiration (threadid={0})",
Thread.CurrentThread.ManagedThreadId);
if (TimerExpired!=null)
TimerExpired(this, EventArgs.Empty);
if (TimerExpired2!=null)
TimerExpired2(this, EventArgs.Empty);
}
private void ChildObjectTimerExpired(Object source, System.EventArgs e)
{
Console.WriteLine("ChildObjectTimerExpired (threadid={0})",
Thread.CurrentThread.ManagedThreadId);
_foreignObjectTimerExpired.Set();
}
public void Run(bool demonstrateProblem)
{
try
{
Console.WriteLine("\nRun()...({0})",
(demonstrateProblem)
? "will demonstrate the problem"
: "will avoid the problem");
int delaySeconds = 4;
AppDomain appDomain = AppDomain.CreateDomain("appDomain2");
string exeAssembly = Assembly.GetEntryAssembly().FullName;
MyObject o = (MyObject) appDomain.CreateInstanceAndUnwrap(exeAssembly,
typeof(MyObject).FullName);
if (demonstrateProblem)
{
// the exception occurs HERE
o.TimerExpired += ChildObjectTimerExpired;
}
else
{
// workaround: don't use an event
o.TimerExpired2 = ChildObjectTimerExpired;
}
_foreignObjectTimerExpired = new ManualResetEvent(false);
o.Go(delaySeconds);
Console.WriteLine("Run(): hosted object will Wait {0} seconds...(threadid={1})",
delaySeconds,
Thread.CurrentThread.ManagedThreadId);
_foreignObjectTimerExpired.WaitOne();
Console.WriteLine("Run(): Done.");
}
catch (System.Exception exc1)
{
Console.WriteLine("In Run(),\n{0}", exc1.ToString());
}
}
public static void Main(string[] args)
{
try
{
var o = new MyObject();
o.Run(true);
o.Run(false);
}
catch (System.Exception exc1)
{
Console.WriteLine("In Main(),\n{0}", exc1.ToString());
}
}
// private fields
private int _timeToSleep;
private ManualResetEvent _foreignObjectTimerExpired;
}
}
【问题讨论】: