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?
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.
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.
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.
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.
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.
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.