Просить общий метод бросить конкретный тип исключения на FAIL

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

Я хочу иметь метод, где я могу сказать "если это плохо, вернитесь с этим типом исключения", правильно?

Например, что-то вроде (и это не работает):

    static ExType TestException<ExType>(string message) where ExType:Exception
    {
        Exception ex1 = new Exception();
        ExType ex = new Exception(message);
        return ex;
    }

Теперь что нас смущает, так это то, что мы ЗНАЕМ, что общий тип будет иметь тип исключения из-за предложения where. Однако код выходит из строя, потому что мы не можем неявно использовать Exception для ExType. Мы также не можем его явно преобразовать, например:

    static ExType TestException<ExType>(string message) where ExType:Exception
    {
        Exception ex1 = new Exception();
        ExType ex = (ExType)(new Exception(message));
        return ex;
    }

Как это не удается... Так что возможно такое? У меня есть сильное чувство, что это будет очень просто, но у меня тяжелый день со старым ноггином, поэтому вырезать мне немного слабину: P


Update

Спасибо за ответы, ребята, похоже, что я не был полным идиотом!;)

ОК, поэтому Vegard и Сэм включил меня в точку, где я мог бы создать правильный тип, но затем явно застрял, потому что параметр сообщения доступен только для чтения после создания экземпляра.

Matt поразил гвоздь прямо на голове своим ответом, я протестировал это, и все работает отлично. Вот пример кода:

    static ExType TestException<ExType>(string message) where ExType:Exception, new ()
    {
        ExType ex = (ExType)Activator.CreateInstance(typeof(ExType), message);
        return ex;
    }

Сладкое!:)

Спасибо, ребята!

Ответ 1

Вы можете сделать это примерно так:

static void TestException<E>(string message) where E : Exception, new()
{
    var e = new E();
    e.Message = message;
    throw e;
}

Однако это не компилируется, потому что Exception.Message только для чтения. Он может быть назначен только путем передачи его конструктору, и нет способа ограничить общий тип чем-то другим, кроме конструктора по умолчанию.

Я думаю, вам придется использовать отражение (Activator.CreateInstance) для "нового" настраиваемого типа исключения с параметром сообщения, например:

static void TestException<E>(string message) where E : Exception
{
    throw Activator.CreateInstance(typeof(E), message) as E;
}

Изменить. К сожалению, вы поняли, что хотите вернуть исключение, а не бросать его. Тот же принцип применяется, поэтому я оставлю свой ответ как есть с заявлениями о выбросах.

Ответ 2

Единственная проблема с решением заключается в том, что можно создать подкласс Exception, который не реализует конструктор с одним строковым параметром, поэтому может быть выбрано исключение MethodMissingException.

static void TestException<E>(string message) where E : Exception, new()
{
    try 
    {
      return Activator.CreateInstance(typeof(E), message) as E;
    } 
    catch(MissingMethodException ex) 
    {
      return new E();
    }
}

Ответ 3

Я создавал встроенный тип исключения, которое я хочу бросить, например:

if (ItemNameIsValid(ItemName, out errorMessage))
    throw new KeyNotFoundException("Invalid name '" + ItemName + "': " + errorMessage);
if (null == MyArgument)
    throw new ArgumentNullException("MyArgument is null");

Ответ 4

Попробовали ли вы:

static T TestException<Exception>(string message)
{}

потому что у меня возникает ощущение, что вложение общего ограничения не требуется, поскольку все бросающиеся исключения должны наследовать от System.Exception в любом случае.

Помните, что generics действительно принимают унаследованные типы.

Ответ 5

Я думаю, что все исключения должны иметь конструктор без параметров и иметь свойство Message, поэтому следующее должно работать:

static ExType TestException<ExType>(string message) where ExType:Exception
{
    ExType ex = new ExType();
    ex.Message = message;
    return ex;
}

Изменить: OK, сообщение только для чтения, поэтому вам нужно будет надеяться, что класс реализует конструктор Exception (string).

static ExType TestException<ExType>(string message) where ExType:Exception
{
    return new ExType(message);
}