.NET:使用 AppDomains 引发和处理事件的问题 [英] .NET: Problem with raising and handling events using AppDomains
问题描述
这是我的问题的基本要点:
Here is the basic gist of my problem:
- 我的主 Window 类实例化了 A 类.
- A 类在辅助 AppDomain 中实例化 B 类.
- B 类引发事件,A 类成功处理该事件.
- A 类引发自己的事件.
问题: 在第 4 步中,当 A 类从捕获 B 类事件的事件处理程序方法中引发其自己的事件时,该事件被引发;然而, Window 类中的订阅处理程序永远不会被调用.
Problem: In step 4, when Class A raises its own event from the event handler method that caught Class B's event, the event is raised; however, the subscribing handler in the Window class is never called.
没有抛出异常.如果我删除辅助 AppDomain,则事件得到处理没有问题.
There are no exceptions being thrown. If I remove the secondary AppDomain, the event gets handled without a problem.
有谁知道为什么这不起作用?有没有另一种方法可以在不使用回调的情况下完成这项工作?
Does anyone know why this doesn't work? Is there another way to make this work without using a callback?
我认为,如果有的话,问题会出现在第 3 步而不是第 4 步中.
I would think, if anything, the problem would occur in step 3 instead of step 4.
这是一个真实的代码示例来说明问题:
Here's a real code sample to illustrate the problem:
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
推荐答案
在我第一次尝试解决这个问题时,我删除了 Class B 对 MarshalByRefObject
的继承和将其标记为可序列化.结果是对象按值进行了封送处理,而我只得到了在主机 AppDomain 中执行的 C 类 的副本.这不是我想要的.
In my first attempt at solving this issue, I removed Class B's inheritance of MarshalByRefObject
and flagged it as serializable instead. The result was the the object was marshaled by value and I just got a copy of Class C that executes in the host AppDomain. This is not what I wanted.
我发现,真正的解决方案是 B 类(示例中的DangerousProgram
)也应该从 MarshalByRefObject
继承,以便 回调也使用代理将线程转换回默认的 AppDomain.
The real solution, I found, was that Class B (DangerousProgram
in the example) should also inherit from MarshalByRefObject
so that the call back also uses a proxy to transition the thread back to the default AppDomain.
顺便说一下,这是一篇很棒的文章我发现 Eric Lippert 以一种非常聪明的方式解释了 marshal by ref 与 marshal by value.
By the way, here's a great article I found by Eric Lippert that explains marshal by ref vs. marshal by value in a very clever way.
这篇关于.NET:使用 AppDomains 引发和处理事件的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!