Как я могу выбросить исключение с определенным HResult?

Я хочу проверить следующий код:

private bool TestException(Exception ex)
{
    if ((Marshal.GetHRForException(ex) & 0xFFFF) == 0x4005)
    {
        return true;
    }
    return false;
}

Я хотел бы как-то настроить объект Exception чтобы вернуть правильный HResult, но я не вижу поля класса Exception которое позволяет это.

Как мне это сделать?

Ответ 1

Я нашел три способа сделать это:

  1. Используйте класс System.Runtime.InteropServices.ExternalException, передав код ошибки в качестве параметра:

    var ex = new ExternalException("-", 0x4005);
    

    Спасибо @HansPassant за его комментарий, объясняющий это.

  2. Передайте ложное исключение, используя наследование для доступа к защищенному полю:

    private class MockException : Exception
    {
        public MockException() { HResult = 0x4005; }
    }
    
    var ex = new MockException();
    
  3. Используйте.NET Reflection, чтобы установить базовое поле:

    BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
    FieldInfo hresultFieldInfo = typeof(Exception).GetField("_HResult", flags);
    
    var ex = new Exception();
    hresultFieldInfo.SetValue(ex, 0x4005);
    

Передача любого из этих исключений методу в вопросе приведет к тому, что метод вернет true. Я подозреваю, что первый метод наиболее полезен.

Ответ 2

Мне полезно создать расширение для этого.

using System.Reflection;

namespace Helper
{
    public static class ExceptionHelper 
    {
       public static Exception SetCode(this Exception e, int value)
       {
           BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
           FieldInfo fieldInfo = typeof(Exception).GetField("_HResult", flags);

           fieldInfo.SetValue(e, value);

           return e;
        }
}

Затем выполните исключение:

using Helper;

public void ExceptionTest()
{
    try
    {
        throw new Exception("my message").SetCode(999);
    }
    catch (Exception e)
    {
        string message = e.Message;
        int code = e.HResult;
    }
}