Rob*_*ers 8 .net events appdomain event-handling
这是我的问题的基本要点:
问题:在第4步中,当A类从捕获B类事件的事件处理程序方法引发自己的事件时,会引发该事件; 但是,从不调用Window类中的订阅处理程序.
没有例外被抛出.如果我删除辅助AppDomain,事件处理没有问题.
有谁知道为什么这不起作用?有没有其他方法可以在不使用回调的情况下完成这项工作?
我认为,如果有的话,问题将发生在第3步而不是第4步.
这是一个真实的代码示例来说明问题:
Class Window1
Private WithEvents _prog As DangerousProgram
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click
_prog = New DangerousProgram()
_prog.Name = "Bad Program"
End Sub
Private Sub MyEventHandler(ByVal sender As Object, ByVal e As NameChangedEventArgs) Handles _prog.NameChanged
TextBox1.Text = "Program's name is now: " & e.Name
End Sub
End Class
<Serializable()> _
Public Class DangerousProgram
Private _appDomain As AppDomain
Private WithEvents _dangerousProgram As Program
Public Event NameChanged(ByVal sender As Object, ByVal e As NameChangedEventArgs)
Public Sub New()
// DangerousPrograms are created inside their own AppDomain for security.
_appDomain = AppDomain.CreateDomain("AppDomain")
Dim assembly As String = System.Reflection.Assembly.GetEntryAssembly().FullName
_dangerousProgram = CType( _
_appDomain.CreateInstanceAndUnwrap(assembly, _
GetType(Program).FullName), Program)
End Sub
Public Property Name() As String
Get
Return _dangerousProgram.Name
End Get
Set(ByVal value As String)
_dangerousProgram.Name = value
End Set
End Property
Public Sub NameChangedHandler(ByVal sender As Object, ByVal e As NameChangedEventArgs) Handles _dangerousProgram.NameChanged
Debug.WriteLine(String.Format("Caught event in DangerousProgram. Program name is {0}.", e.Name))
Debug.WriteLine("Re-raising event...")
RaiseEvent NameChanged(Me, New NameChangedEventArgs(e.Name))
End Sub
End Class
<Serializable()> _
Public Class Program
Inherits MarshalByRefObject
Private _name As String
Public Event NameChanged(ByVal sender As Object, ByVal e As NameChangedEventArgs)
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
RaiseEvent NameChanged(Me, New NameChangedEventArgs(_name))
End Set
End Property
End Class
<Serializable()> _
Public Class NameChangedEventArgs
Inherits EventArgs
Public Name As String
Public Sub New(ByVal newName As String)
Name = newName
End Sub
End Class
Run Code Online (Sandbox Code Playgroud)
小智 31
.NET事件的神奇之处在于,当您通过A的实例订阅B实例中的事件时,A会被发送到B的appdomain中.如果A不是MarshalByRef,则发送A的值副本.现在你有两个独立的A实例,这就是你遇到意外行为的原因.
如果有人很难理解这是如何发生的,我建议采用以下解决方法,这使得事件以这种方式表现的原因显而易见.
为了在B中(在appdomain 2内)引发"事件"并在A中(在appdomain 1内)处理它们而不使用真实事件,我们需要创建第二个对象来转换方法调用(跨越边界而不用太多ado)事件(不按预期行事).这个类,我们称之为X,将在appdomain 1中实例化,其代理将被发送到appdomain 2.这是代码:
public class X : MarshalByRefObject
{
public event EventHandler MyEvent;
public void FireEvent(){ MyEvent(this, EventArgs.Empty); }
}
Run Code Online (Sandbox Code Playgroud)
伪代码将类似于:
为了让B在AD1中重新触发事件,它不仅必须具有该方法,还必须具有触发该方法的实例.这就是我们必须将代理X发送到AD2的原因.这也是跨域事件需要跨域边界编组事件处理程序的原因! 事件只是方法执行的一个奇特的包装器.要做到这一点,你不仅需要方法,还需要实例来执行它.
经验法则必须是,如果您希望跨应用程序域边界处理事件,则两种类型 - 暴露事件和处理事件的类型 - 必须扩展MarshalByRefObject.