关于.net:Visual Studio不会在C#中显示重新抛出的内部异常的原始位置

Visual Studio does not show the original location of rethrown inner exception in C#

因此,我遵循了推荐的答案,即如何在不丢失堆栈跟踪的情况下重新引发TargetInvocationException的内部异常,最终得到如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// Inside DpmEntrypoint static class.
public static object Invoke(Delegate d, object[] args)
{
    try
    {
        // Invoke directly if not networked.
        if (LocalNode.Singleton == null)
            return d.DynamicInvoke(args);

        // Get the network name of the object and the name of the method.
        string objectName = (d.Target as ITransparent).NetworkName;
        string methodName = d.Method.Name;

        // Get our local node and invoke the method.
        return LocalNode.Singleton.Invoke(objectName, methodName, args);
   }
   catch (Exception ex)
   {
        ex.Rethrow();
        return null;
    }
}

// Inside ExceptionExtensions static class.
public static void Rethrow(this Exception ex)
{
    if (ex is TargetInvocationException)
        ex.InnerException.Rethrow();
    else
    {
        typeof(Exception).GetMethod("PrepForRemoting",
            BindingFlags.NonPublic | BindingFlags.Instance)
            .Invoke(ex, new object[0]);
        throw ex;
    }
}

在这种情况下,后处理器在编译时后运行程序集,指定的方法包装在委托中,并使用上述方法调用。为了随后调用委托,我必须在一行中的某个地方使用invoke(即使它在singleton.invoke内部使用的反射中)。

上面的rethrow方法正确地保留了堆栈跟踪,如下所示:

Server stack trace:
at Example.ExampleController.NullTest() in C:\Server Storage\Projects
edpoint\Pivot\Example\ExampleController.cs:line 19
at Example.ExampleWorld.t_Spawned(Object sender, EventArgs e) in C:\Server Storage\Projects
edpoint\Pivot\Example\ExampleWorld.cs:line 29
at Pivot.Core.Actor.OnSpawned__Distributed0() in C:\Server Storage\Projects
edpoint\Pivot\Pivot.Core\Actor.cs:line 62

Exception rethrown at [0]:
at Process4.Providers.ExceptionExtensions.Rethrow(Exception ex)
at Process4.Providers.ExceptionExtensions.Rethrow(Exception ex)
at Process4.Providers.DpmEntrypoint.Invoke(Delegate d, Object[] args)
at Pivot.Core.Actor.OnSpawned()
at Pivot.Core.GameInfo.set_World__Distributed0(WorldInfo value) in C:\Server Storage\Projects
edpoint\Pivot\Pivot.Core\GameInfo.cs:line 35

Exception rethrown at 1:
at Process4.Providers.ExceptionExtensions.Rethrow(Exception ex)
at Process4.Providers.ExceptionExtensions.Rethrow(Exception ex)
at Process4.Providers.DpmEntrypoint.SetProperty(Delegate d, Object[] args)
at Pivot.Core.GameInfo.set_World(WorldInfo value)
at Example.ExampleGame.t_Spawned(Object sender, EventArgs e) in C:\Server Storage\Projects
edpoint\Pivot\Example\ExampleGame.cs:line 25
at Pivot.Core.Actor.OnSpawned__Distributed0() in C:\Server Storage\Projects
edpoint\Pivot\Pivot.Core\Actor.cs:line 62

Exception rethrown at [2]:
at Process4.Providers.ExceptionExtensions.Rethrow(Exception ex)
at Process4.Providers.ExceptionExtensions.Rethrow(Exception ex)
at Process4.Providers.DpmEntrypoint.Invoke(Delegate d, Object[] args)
at Pivot.Core.Actor.OnSpawned()
at Pivot.Engine.set_Game(GameInfo value) in C:\Server Storage\Projects
edpoint\Pivot\Pivot.Core\Engine.cs:line 47
at Example.Program.Main(String[] args) in C:\Server Storage\Projects
edpoint\Pivot\Example\Program.cs:line 14
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

但我遇到的问题是,即使在以发布模式编译库时,Visual Studio仍然在rethrow处显示异常源,而不是在nulltest处显示异常源(在这里引发nullreferenceexception)。

由于应用程序中的所有方法都将被挂接,因此对开发人员来说,抛出TargetInvocationException是无用的;他们更感兴趣的是原始异常在其代码中出现的位置。

如果不能像现在那样重新传递内部异常,它基本上会在与分布式处理库一起使用时在.NET中生成整个异常系统,而开发人员不知道幕后发生了什么(这与库的目标正好相反)。

有人知道让Visual Studio在最初抛出的位置显示它的方法吗?

编辑:

我正在考虑用C++来解决这个问题,因为它让我访问了一些特殊功能,如MSDN文章中描述的,在线程之间传输异常。

问题是,这些函数不允许我"传输托管异常",因此当我尝试在托管异常上使用它时,rethrow_异常会引发sehexception。如果有人知道解决这个问题的方法,那么它可以用C++/CLI来解决(如果只有一个方法得到当前异常的精确指针,那么可以使用重新投掷IL指令!).

1
2
3
4
5
6
7
8
9
10
11
12
13
namespace Rethrow {
    [System::Runtime::CompilerServices::Extension]
    public ref class ExceptionExtensions abstract sealed
    {
    public:
        [System::Runtime::CompilerServices::Extension]
        static void Rethrow(System::Exception^ s)
        {
            std::rethrow_exception(std::copy_exception<System::Exception^>(s));
            throw;
        }
    };
}


我设法通过修改后处理器来解决这个问题,通过匹配的委托直接调用方法(因为后处理器在运行时知道方法签名,并且可以生成适当的匹配委托)。在委托上使用invoke()时,它不会用targetInvocationException包装任何异常;只有在动态调用方法时才会发生这种情况。

不幸的是,这个解决方案实际上并不能解决动态调用方法和传递内部异常的问题;它只是利用了这个特定库的构建过程中已经存在的后处理器(即,这个解决方案并不能解决任何构建不进行后处理的库的人的问题)。


throw ex;将展开堆栈。

1
2
3
4
5
catch (Exception ex)
{
    throw;
    return null;
}

就够了。但请记住,这是C语法。


六羟甲基三聚氰胺六甲醚。。。尝试将"throw ex"替换为以下结构:

1
2
Exception HighelLevelException = new Exception("An inner error occured!", ex);
throw HighelLevelException;