1

此类存在于它自己的 DLL 中。调用 Ex 方法很明显会导致抛出和处理异常:

class Foo : MarshalByRefObject
{
    public void Ex()
    {
        object o = null;

        try
        {
            string s = o.ToString();
        }
        catch { }
    }
}

下面将包含 Foo 的 DLL 加载到另一个 AppDomain 中,创建一个 Foo 并调用 Ex 方法。

using System;
using System.Diagnostics;
using System.Runtime.ExceptionServices;
using RemoteCode;

namespace AppDomainTraceTest
{
    class Program
    {
        static void Main()
        {
            AppDomain appDomain = AppDomain.CreateDomain("TEST",
                null,
                new AppDomainSetup
                {
                    ApplicationBase = AppDomain.CurrentDomain.BaseDirectory
                });

            // appDomain.FirstChanceException +=
            //     (s, e) => Debug.WriteLine("* " + e.Exception.Message);

            Bar bar = new Bar();
            bar.Subscribe(appDomain);

            Foo foo = (Foo)appDomain.CreateInstance("RemoteCode", "RemoteCode.Foo").Unwrap();
            foo.Ex();
        }
    }

    public class Bar : MarshalByRefObject
    {
        public void Subscribe(AppDomain ad)
        {
            ad.FirstChanceException += OnFirstChanceException;
        }

        private void OnFirstChanceException(object sender, FirstChanceExceptionEventArgs e)
        {
            Debug.WriteLine("* " + e.Exception.Message);
        }
    }
}

结果是一个 FatalExecutionEngineError:

运行时遇到致命错误。错误地址位于线程 0x26f0 上的 0x62c6529d。错误代码为 0x80131506。此错误可能是 CLR 中的错​​误或用户代码的不安全或不可验证部分中的错误。此错误的常见来源包括 COM 互操作或 PInvoke 的用户封送错误,这可能会损坏堆栈。

它发生在 Foo 的这一行:

string s = o.ToString();

如果我注释掉包括 Bar 在内的行,并取消注释前一行,则代码工作正常,异常消息将写入调试控制台:

appDomain.FirstChanceException +=
    (s, e) => Debug.WriteLine("* " + e.Exception.Message);

//Bar bar = new Bar();
//bar.Subscribe(appDomain);

Foo foo = (Foo)appDomain.CreateInstance("RemoteCode", "RemoteCode.Foo").Unwrap();
foo.Ex();

我是在做一些愚蠢的事情,还是这是一个错误?

4

1 回答 1

1

在这种情况下,标签“bug”非常合适,纯托管代码不应该有 FEEE。但是,您给 CLR 带来了极大的困难,在非常关键的时刻将事件处理程序调用从一个 AppDomain 编组到另一个。显然它没有能力处理这个问题。

您需要强烈考虑避免这种情况。只要您将事件处理程序保留在同一个 AppDomain 中,它就可以正常工作。这很好用,例如:

public class Foo : MarshalByRefObject {
    public Foo() {
        AppDomain.CurrentDomain.FirstChanceException += (s, e) => {
            Debug.WriteLine("* " + e.Exception.Message);
        };
    }
    // etc...
}

我想可能不方便记录。您可以在 connect.microsoft.com 提交此错误的反馈报告

于 2013-10-09T15:53:35.027 回答