.NET:使用 AppDomains 引发和处理事件的问题 [英] .NET: Problem with raising and handling events using AppDomains

查看:24
本文介绍了.NET:使用 AppDomains 引发和处理事件的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的问题的基本要点:

Here is the basic gist of my problem:

  1. 我的主 Window 类实例化了 A 类.
  2. A 类在辅助 AppDomain 中实例化 B 类.
  3. B 类引发事件,A 类成功处理该事件.
  4. 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 BMarshalByRefObject 的继承和将其标记为可序列化.结果是对象按值进行了封送处理,而我只得到了在主机 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆