Visual Studio在C#中不显示重新抛出的内部异常的原始位置。
Visual Studio在C#中不显示重新抛出的内部异常的原始位置。
在这种情况下,编译后会在程序集上运行一个后处理器,并且指定的方法会被封装在一个委托中并使用上述方法调用。为了调用委托,我必须在某个地方使用Invoke(即使在Singleton.Invoke中使用的是反射)。
上述的Rethrow方法可以正确地保留堆栈跟踪,如下所示:
服务器堆栈跟踪:
在 C:\Server Storage\Projects\Redpoint\Pivot\Example\ExampleController.cs 的第19行调用 Example.ExampleController.NullTest()
在 C:\Server Storage\Projects\Redpoint\Pivot\Example\ExampleWorld.cs 的第29行调用 Example.ExampleWorld.t_Spawned(Object sender, EventArgs e)
在 C:\Server Storage\Projects\Redpoint\Pivot\Pivot.Core\Actor.cs 的第62行调用 Pivot.Core.Actor.OnSpawned__Distributed0()
[0]重新抛出的异常:
在 Process4.Providers.ExceptionExtensions.Rethrow(Exception ex)
在 Process4.Providers.ExceptionExtensions.Rethrow(Exception ex)
在 Process4.Providers.DpmEntrypoint.Invoke(Delegate d, Object[] args)
在 Pivot.Core.Actor.OnSpawned()
在 C:\Server Storage\Projects\Redpoint\Pivot\Pivot.Core\GameInfo.cs 的第35行调用 Pivot.Core.GameInfo.set_World__Distributed0(WorldInfo value)
1重新抛出的异常:
在 Process4.Providers.ExceptionExtensions.Rethrow(Exception ex)
在 Process4.Providers.ExceptionExtensions.Rethrow(Exception ex)
在 Process4.Providers.DpmEntrypoint.SetProperty(Delegate d, Object[] args)
在 Pivot.Core.GameInfo.set_World(WorldInfo value)
在 C:\Server Storage\Projects\Redpoint\Pivot\Example\ExampleGame.cs 的第25行调用 Example.ExampleGame.t_Spawned(Object sender, EventArgs e)
在 C:\Server Storage\Projects\Redpoint\Pivot\Pivot.Core\Actor.cs 的第62行调用 Pivot.Core.Actor.OnSpawned__Distributed0()
[2]重新抛出的异常:
在 Process4.Providers.ExceptionExtensions.Rethrow(Exception ex)
在 Process4.Providers.ExceptionExtensions.Rethrow(Exception ex)
在 Process4.Providers.DpmEntrypoint.Invoke(Delegate d, Object[] args)
在 Pivot.Core.Actor.OnSpawned()
在 C:\Server Storage\Projects\Redpoint\Pivot\Pivot.Core\Engine.cs 的第47行调用 Pivot.Engine.set_Game(GameInfo value)
在 C:\Server Storage\Projects\Redpoint\Pivot\Example\Program.cs 的第14行调用 Example.Program.Main(String[] args)
在 System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
在 System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
在 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
在 System.Threading.ThreadHelper.ThreadStart_Context(Object state)
在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
在 System.Threading.ThreadHelper.ThreadStart()
但我遇到的问题是,即使在Release模式下编译库,Visual Studio仍然在Rethrow处显示异常源,而不是NullTest(NullReferenceException抛出的位置)。
由于应用程序中的所有方法都将被hook,因此将TargetInvocationException原样抛出对开发人员来说是无用的;他们更关心原始异常在他们的代码中发生的位置。
如果没有能力将内部异常原样抛出,那么在与分布式处理库一起使用时,整个.NET异常系统基本上变得无用,而开发人员却不知道背后发生了什么(这与库的完全相反的目标)。
有人知道如何使Visual Studio显示它最初抛出的位置吗?
编辑:
我考虑使用C++/CLI解决此问题,因为它使我能够访问MSDN文章Transporting Exceptions Between Threads中描述的一些特殊功能。
问题是,这些函数不允许我“传输托管异常”,因此当我尝试在托管异常上使用它们时,rethrow_exception会引发SEHException。如果有人知道如何解决这个问题,那么可以使用C++/CLI解决它(如果只有一种方法可以获得当前异常的确切指针,那么就可以使用rethrow IL指令!)。
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
throw;
}
};
}
问题的原因是在C#中,当使用`throw`语句重新抛出内部异常时,Visual Studio无法显示原始位置。这是因为内部异常被重新包装在一个`TargetInvocationException`中,导致无法准确地追踪到原始位置。
解决方法是修改后处理器,通过匹配的委托直接调用方法(因为后处理器在运行时了解方法签名并可以生成适当的匹配委托)。当使用委托的`Invoke()`方法时,不会将任何异常包装在`TargetInvocationException`中;这仅在动态调用方法时发生。
不幸的是,这个解决方法实际上并没有解决动态调用方法和传递内部异常的问题;它只是利用了已经存在于构建过程中的后处理器(即这个解决方法并不能解决那些没有进行后处理的库的问题)。
在C#中,使用throw ex;
语句会将异常向上回溯到调用栈。而catch (Exception ex) { throw; return null; }
语句足够了,这是C#语法。但需要记住,这样做只会重新抛出TargetInvocationException异常,而不是重新抛出内部异常。
出现这个问题的原因是在异常处理中,使用了throw ex;
语句。这个语句会将异常重新抛出,但会丢失原始异常的堆栈跟踪信息。因此,在Visual Studio中无法显示内部异常的原始位置。
要解决这个问题,可以使用throw;
语句来重新抛出异常,而不是throw ex;
。这样做可以保留原始异常的堆栈跟踪信息,使得在Visual Studio中能够正确显示内部异常的原始位置。
以下是修复后的代码:
catch (Exception ex) { throw; return null; }
通过使用throw;
语句重新抛出异常,可以确保在Visual Studio中正确显示内部异常的原始位置。这样可以更方便地调试和定位问题。
在C#中,使用throw ex;
语句会丢失原始异常的堆栈跟踪信息,导致在Visual Studio中无法显示内部异常的原始位置。为了解决这个问题,应该使用throw;
语句来重新抛出异常,以保留原始异常的堆栈跟踪信息。这样可以方便地调试和定位问题。
问题的出现原因是,当在C#中使用try-catch语句重新抛出内部异常时,Visual Studio无法显示内部异常的原始位置。解决方法是使用一个新的异常对象来重新抛出内部异常,并将原始异常作为参数传递给新的异常对象。
以下是解决方法的代码示例:
try { // some code that may throw an exception } catch (Exception ex) { Exception newException = new Exception("An inner error occurred!", ex); throw newException; }
通过这种方式,重新抛出的异常将具有与原始异常相同的类型,并且可以在调试过程中显示原始异常的位置。这样,开发人员就可以更容易地追踪和调试代码中的问题。