He estado escribiendo mucho código recientemente que involucra interoperabilidad con la API Win32 y he empezado a preguntarme cuál es la mejor forma de lidiar con errores nativos (no administrados) causados por llamadas a funciones API de Windows .Lanzando una excepción Win32Exception
Actualmente, las llamadas a funciones nativas tienen el siguiente aspecto:
// NativeFunction returns true when successful and false when an error
// occurred. When an error occurs, the MSDN docs usually tell you that the
// error code can be discovered by calling GetLastError (as long as the
// SetLastError flag has been set in the DllImport attribute).
// Marshal.GetLastWin32Error is the equivalent managed function, it seems.
if (!WinApi.NativeFunction(param1, param2, param3))
throw new Win32Exception();
La línea que plantea la excepción se puede reescribir de manera equivalente, como tal, yo creo:
throw new Win32Exception(Marshal.GetLastWin32Error());
Ahora bien, esto es todo bien porque arroja una excepción que contiene adecuadamente el código de error Win32 que se estableció, así como una descripción (generalmente) legible para humanos del error como la propiedad Message
del objeto Exception. Sin embargo, he estado pensando que sería aconsejable modificar/ajustar al menos algunas de estas excepciones, si no todas, para que den un mensaje de error ligeramente más orientado al contexto, es decir, una más significativa en cualquier situación en que se encuentre el código nativo. siendo utilizado. He considerado varias alternativas para esto:
Especificación de un mensaje de error personalizado en el constructor de
Win32Exception
.throw new Win32Exception(Marshal.GetLastWin32Error(), "My custom error message.");
Envolver la
Win32Exception
en otro objeto excepción de modo que tanto el código de error original y el mensaje se conservan (laWin32Exception
es ahora laInnerException
de la excepción de los padres).throw new Exception("My custom error message.", Win32Exception(Marshal.GetLastWin32Error()));
El mismo que 2, excepto que usando otro
Win32Exception
como la excepción envoltura.Lo mismo que 2, excepto que se usa una clase personalizada derivada de
Exception
como la excepción de envoltura.Igual que 2, excepto que se usa una excepción BCL (Biblioteca de clases base) como padre cuando es apropiado. No estoy seguro si es apropiado incluso configurar el
InnerException
en elWin32Exception
en este caso (tal vez para un contenedor de bajo nivel pero no una interfaz de nivel superior/abstraída que no hace obvio que la interoperabilidad de Win32 ocurre detrás de las escenas).
Esencialmente lo que quiero saber es: ¿cuál es la práctica recomendada para tratar los errores de Win32 en .NET? Lo veo hecho en código abierto en todo tipo de formas diferentes, pero tenía curiosidad de si había alguna guía de diseño. Si no, me interesarían sus preferencias personales aquí. (¿Tal vez incluso no utiliza ninguno de los métodos anteriores?)
+1 para la información adicional: hay poco, si acaso, más frustrante que obtener una excepción de "Archivo no encontrado" sin referencia a qué archivo no se puede encontrar. –
@Earwicker: Haces un punto justo ... Además, estoy haciendo esta pregunta específicamente en relación con Win32Exception porque a menudo (aunque no siempre) tiende a ser bastante vago e inútil, como señala Harper. – Noldorin
Para aclarar su último párrafo, ¿quiere decir que es mejor adjuntar también el mensaje de error interno * como para envolverlo como la excepción interna? – Noldorin