在C ++ / CLI包装器类中转换异常的最佳实践

时间:2021-04-03 19:48:00

I am writing a .NET wrapper class for an existing native class which throws exceptions. What are the best practices for translating between native C++ exceptions and Managed exceptions? Catch and re-throw on a one-to-one basis (e.g. std::invalid_argument -> System.System.ArgumentException)? Is there a mapping already drawn up somewhere?

我正在为一个抛出异常的现有本机类编写一个.NET包装类。在本机C ++异常和托管异常之间进行转换的最佳实践是什么?一对一地抓住并重新抛出(例如std :: invalid_argument - > System.System.ArgumentException)?是否已在某处绘制了映射?

4 个解决方案

#1


4  

There is no standard mapping that I know of. What I've done in the past is translate the ones I know about, and a catch block for System.Runtime.InteropServices.SEHException. All non-translated exceptions will be turned into that exception. As long as you have a debug build of the code that is throwing the exception, you should get a nice stack trace. Then you can go and look at the exception and write the wrapper.

我不知道有标准的映射。我过去所做的是翻译我所知道的,以及System.Runtime.InteropServices.SEHException的catch块。所有未翻译的异常都将变为该异常。只要您有抛出异常的代码的调试版本,就应该获得一个很好的堆栈跟踪。然后你可以去查看异常并编写包装器。

But on the last project I had to do this on, I went with something much more simple, I ended up writing a couple of System.Exception derivatives for logic_error and runtime_error. Then I would catch those 2 base classes and use typeid(err) to write the .NET message that got thrown. This way I didn't "lose" what was being thrown from the C++ but didn't have to map everything except the most important ones.

但是在最后一个项目上,我必须做的更简单,我最后为logic_error和runtime_error编写了几个System.Exception派生物。然后我会捕获这两个基类并使用typeid(错误)来编写抛出的.NET消息。这样我就不会“丢失”从C ++中抛出的内容,但除了最重要的内容之外,没有必要映射所有内容。

#2


2  

One-to-one mapping seems the sanest approach to me. "Universal" mapping is hardly possible because of application-specific exceptions, although there is some obvious mapping for STL exception classes.

一对一的映射对我来说似乎是最诚实的方法。由于特定于应用程序的异常,“通用”映射几乎不可能,尽管STL异常类有一些明显的映射。

Also there is an issue of SEH exceptions from unmanaged code. Depending on your situation it might be necessary to catch and wrap them too.

此外,还存在来自非托管代码的SEH异常问题。根据您的情况,可能需要捕捉并包裹它们。

#3


2  

I think it depends on the design of the wrapper. If the manager wrapper's interface will be nearly identical to the unmanaged library's interface, then rethrow the exceptions 1:1. If you're changing the interface significantly, then throw exceptions most appropriate for the new interface. Either way, make sure the wrapper throws exceptions any time an operation cannot be completed to be consistent with .NET design guidelines.

我认为这取决于包装器的设计。如果管理器包装器的接口与非托管库的接口几乎相同,则重新抛出异常1:1。如果您正在显着更改接口,则抛出最适合新接口的异常。无论哪种方式,确保包装器在无法完成操作时抛出异常以符合.NET设计准则。

#4


1  

What are you really trying to do?

你真的想做什么?

Interop already translates native exceptions to managed, including SEH exceptions. However, good design dictates that ALL exceptions should be caught at the native API level. You shouldnt deviate from this unless there is a good reason. We dont know enough about your design.

Interop已将本机异常转换为托管,包括SEH异常。但是,良好的设计要求所有异常都应该在本机API级别捕获。除非有充分的理由,否则你不应该偏离这一点。我们对你的设计知之甚少。

#1


4  

There is no standard mapping that I know of. What I've done in the past is translate the ones I know about, and a catch block for System.Runtime.InteropServices.SEHException. All non-translated exceptions will be turned into that exception. As long as you have a debug build of the code that is throwing the exception, you should get a nice stack trace. Then you can go and look at the exception and write the wrapper.

我不知道有标准的映射。我过去所做的是翻译我所知道的,以及System.Runtime.InteropServices.SEHException的catch块。所有未翻译的异常都将变为该异常。只要您有抛出异常的代码的调试版本,就应该获得一个很好的堆栈跟踪。然后你可以去查看异常并编写包装器。

But on the last project I had to do this on, I went with something much more simple, I ended up writing a couple of System.Exception derivatives for logic_error and runtime_error. Then I would catch those 2 base classes and use typeid(err) to write the .NET message that got thrown. This way I didn't "lose" what was being thrown from the C++ but didn't have to map everything except the most important ones.

但是在最后一个项目上,我必须做的更简单,我最后为logic_error和runtime_error编写了几个System.Exception派生物。然后我会捕获这两个基类并使用typeid(错误)来编写抛出的.NET消息。这样我就不会“丢失”从C ++中抛出的内容,但除了最重要的内容之外,没有必要映射所有内容。

#2


2  

One-to-one mapping seems the sanest approach to me. "Universal" mapping is hardly possible because of application-specific exceptions, although there is some obvious mapping for STL exception classes.

一对一的映射对我来说似乎是最诚实的方法。由于特定于应用程序的异常,“通用”映射几乎不可能,尽管STL异常类有一些明显的映射。

Also there is an issue of SEH exceptions from unmanaged code. Depending on your situation it might be necessary to catch and wrap them too.

此外,还存在来自非托管代码的SEH异常问题。根据您的情况,可能需要捕捉并包裹它们。

#3


2  

I think it depends on the design of the wrapper. If the manager wrapper's interface will be nearly identical to the unmanaged library's interface, then rethrow the exceptions 1:1. If you're changing the interface significantly, then throw exceptions most appropriate for the new interface. Either way, make sure the wrapper throws exceptions any time an operation cannot be completed to be consistent with .NET design guidelines.

我认为这取决于包装器的设计。如果管理器包装器的接口与非托管库的接口几乎相同,则重新抛出异常1:1。如果您正在显着更改接口,则抛出最适合新接口的异常。无论哪种方式,确保包装器在无法完成操作时抛出异常以符合.NET设计准则。

#4


1  

What are you really trying to do?

你真的想做什么?

Interop already translates native exceptions to managed, including SEH exceptions. However, good design dictates that ALL exceptions should be caught at the native API level. You shouldnt deviate from this unless there is a good reason. We dont know enough about your design.

Interop已将本机异常转换为托管,包括SEH异常。但是,良好的设计要求所有异常都应该在本机API级别捕获。除非有充分的理由,否则你不应该偏离这一点。我们对你的设计知之甚少。