gpt4 book ai didi

.NET:使用AppDomains引发和处理事件的问题

转载 作者:行者123 更新时间:2023-12-04 04:45:19 26 4
gpt4 key购买 nike

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

  • 我的主要Window类实例化A类。
  • A类在次要AppDomain 中实例化B类。
  • B类引发一个事件,而A类成功处理该事件。
  • A类引发自己的事件。

  • 问题:在步骤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

    最佳答案

    .NET事件的魔力掩盖了一个事实,当您通过A的实例在B的实例中预订事件时,A便被发送到B的appdomain中。如果A不是MarshalByRef,则发送A的值副本。现在,您有两个单独的A实例,这就是为什么您遇到意外行为的原因。

    如果有人很难理解这种情况如何发生,我建议采用以下变通办法,这很明显使事件以这种方式表现出来。

    为了在B中(在appdomain 2内)引发“事件”并在A中(在appdomain 1内)处理它们而不使用真实事件,我们需要创建第二个对象来翻译方法调用(不费吹灰之力就跨越边界)事件(行为不符合您的预期)。将该类称为X,将在appdomain 1中实例化,并将其代理发送到appdomain2。这是代码:

    public class X : MarshalByRefObject
    {
    public event EventHandler MyEvent;
    public void FireEvent(){ MyEvent(this, EventArgs.Empty); }
    }

    伪代码将类似于:
  • AD1 中的创建一个新的应用程序域。将其称为 AD2
  • 调用 AD2 上的CreateInstanceAndww。 AD 2 中现在存在 B ,而 AD1 中存在 B(代理)
  • 创建一个 X 的实例。
  • A X B(代理)
  • AD2 中, B 现在有一个 X(代理)的实例( X MBRO)
  • AD1 中, X注册事件处理程序。
  • AD2 中, B 调用 X(proxy).FireEvent()
  • AD1 中,FireEvent在 X 上执行,从而触发MyEvent
  • 执行FireEvent的事件处理程序。

  • 为了使 B AD1 中触发一个事件,它不仅必须具有该方法,而且还必须具有实例来触发该方法。这就是为什么我们必须将 X 的代理发送到 AD2 的原因。这也是为什么跨域事件要求将事件处理程序跨域限制编码的原因!事件只是方法执行周围的奇特包装。为此,您不仅需要方法,还需要实例来执行该方法。

    经验法则是,如果您希望跨应用程序域边界处理事件,则两种类型(一种公开事件,另一种处理事件)必须扩展MarshalByRefObject。

    关于.NET:使用AppDomains引发和处理事件的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1277346/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com