Расширение исключений в Powershell с сообщением по умолчанию

Я пытался обдумать расширение исключений в PowerShell. Мой первый проход в классе выглядит так...

class CustomException : Exception {
    CustomException () {
    }
    CustomException ([String] $message) : base ($message) {
    }
}

И использование соответствует ожиданиям: первый подход здесь создает имя типа, а второй - предоставленное сообщение...

try {
    throw [CustomException]
} catch {
    "$($_.Exception.Message)"
}
try {
    throw [CustomException] 'Another message'
} catch {
    "$($_.Exception.Message)"
}

Однако я действительно хочу иметь сообщение по умолчанию, поэтому я могу использовать первый пример во многих местах, но если я хочу пересмотреть сообщение, я могу сделать это один раз в классе. Или, возможно, даже локализовать сообщение в какой-то момент. Этот поток кажется, что это возможно в C#, особенно последние два поста. Итак, возьмем последний пример...

public class MyException : Exception
{
    public MyException () : base("This is my Custom Exception Message")
    {
    }
}

Я думал, что смогу сделать то же самое в Powershell, вот так...

CustomException () : base ('Default message') {
}

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

try {
    throw [System.IO.FileNotFoundException]
} catch {
    "$($_.Exception.Message)"
}

И это ТАКЖЕ не предоставляет сообщение по умолчанию, только имя класса. Итак, этот код C# не делает то, что я думаю? Или это просто разница в поведении в Powershell? Или я что-то не так делаю?


person Gordon    schedule 08.06.2020    source источник
comment
Странно, добавление : base("default message") к конструктору по умолчанию отлично работает для меня. Какую именно версию PowerShell вы используете?   -  person Mathias R. Jessen    schedule 08.06.2020
comment
@mathias-r-jessen Я в 5.1. Я наконец-то отвык от 2.0, но я не могу заставить людей перейти на Core.   -  person Gordon    schedule 08.06.2020
comment
Я просто заметил, чего не хватает, смотрите мой ответ   -  person Mathias R. Jessen    schedule 08.06.2020


Ответы (1)


То, что вы хотите, отлично поддерживается, но вам нужно создать экземпляр исключения!

Синтаксис throw в основном:

throw [Throwable]

где Throwable — это либо ErrorRecord, либо Exception, либо строка (в основном простое сообщение об ошибке).

Когда вы выдаете литерал типа [CustomException], PowerShell преобразует это выражение в [string], поэтому вы просто видите имя типа в блоке catch.

Для правильного создания экземпляра исключения требуется вызов конструктора:

class CustomException : Exception
{
  CustomException() : base("default CustomException message goes here")
  {
  }
}

try {
    throw [CustomException]::new()    # <-- don't forget to call the constructor
} catch {
    "$_"
}
person Mathias R. Jessen    schedule 08.06.2020
comment
@mathias-r-jessen А, очень интересно. Я правильно понимаю, что это уникально для Powershell, или это нюанс, который просто не упоминался в примере C#? И лучше ли всегда использовать такой конструктор или throw [System.IO.FileNotFoundException] совершенно допустимо, если допустимо получение имени типа в качестве сообщения? Для согласованности мне кажется, что я мог бы также использовать throw [CustomException]::new('Another message'). - person Gordon; 08.06.2020
comment
throw [System.IO.FileNotFoundException] на самом деле приводит к throw 'System.IO.FileNotFoundException' - это допустимо, но на самом деле это не исключение того типа, который вы ожидаете - person Mathias R. Jessen; 08.06.2020
comment
@mathias-r-jessen Это потому, что [System.IO.FileNotFoundException] разрешается в строку через .ToString()? Не столько это имеет значение, сколько мне интересно, начинаю ли я наконец что-то понимать. - person Gordon; 08.06.2020
comment
@ Гордон, да, точно! throw принимает только три типа аргументов: ErrorRecord, Exception или строки, поэтому, если не один из двух первых, powershell преобразуется в строку - person Mathias R. Jessen; 08.06.2020