Как включить дополнительную информацию в исключения библиотеки

1

Я работаю над библиотекой, и я хочу включить дополнительную контекстуальную информацию во все исключения, которые выбрасываются из библиотеки, в том числе в исключениях, которые не являются специфичными для библиотеки, например System.NullReferenceException. (Скорее всего, эта дополнительная информация поможет разработчикам отладить проблемы с их кодом и/или данными.) EDIT: Моя библиотека обрабатывает некоторые большие структуры данных, которые также могут быть очень вложенными. Поэтому я хочу включить в качестве дополнительной информации полный путь поля, который обрабатывается при MyClass.Field1.SomeArray[10].SomeOtherField.ThisFails исключения, например MyClass.Field1.SomeArray[10].SomeOtherField.ThisFails. (Я думаю, что в этом случае это будет очень полезная информация для добавления исключений).

Решение 1. Я знаю, что упаковка является рекомендуемым способом включения дополнительной контекстной информации в исключения. Но я думаю, что это имеет большой недостаток: вы должны изменить тип исключений. Таким образом, например, OutOfMemoryException будет обернуто в конкретное исключение библиотеки, и приложение будет более сложно обрабатывать это конкретное исключение (разработчикам придется проверять тип свойства InnerException). Поэтому я хочу избежать исключения исключений. (Дополнительным соображением против упаковки является то, что моя библиотека будет работать с некоторыми объектами, реализованными пользователями, что может вызывать определенные исключения, и я не хочу изменять тип этих исключений.)

Решение 2. Я решил использовать словарь Exception.Data чтобы включить эту дополнительную информацию в исключения. Недостатком этого решения является то, что дополнительная информация не будет включена в результат реализации Exception.ToString() по умолчанию. (Я хотел бы включить дополнительную информацию в результат Exception.ToString(), чтобы она была легко видна разработчикам, которые регистрируют исключения с чем-то вроде log.Write(ex.ToString()); разработчики не узнают, как вызывать другой метод форматирования из моей библиотеки.)

EDIT: Решение 3. Я думал о добавлении моей информации в конце exception.Message Поле сообщения с использованием рефлексии (так как это readolnly). Есть ли веские причины, почему я должен избегать этого?

Есть ли другие возможные решения этой проблемы, которые позволят избежать объясненных недостатков? Если нет других лучших решений, какая из них является наиболее распространенной?

EDIT: хочу пояснить, так как это библиотека, у меня нет большого контроля над тем, какую регистрацию исключений будет использовать пользователь, и какую часть документации библиотеки они будут читать. Я хочу избежать бессмысленных запросов поддержки, включив как можно больше информации в результат ex.ToString().

Кроме того, производительность важна для этой библиотеки (это может быть только для маркетинга, но тогда это еще более важно), поэтому для сценариев с хорошим поведением я хочу избежать дополнительной обработки. То есть, если это возможно, я также хочу избежать некоторых дополнительных проверок, например if (data.Field == null) throw new ArgumenNullException("someField"); поскольку, если что-то не так с данными, код будет просто немного позже с NullReferenceException, который я могу поймать в удобном месте и использовать некоторый метод для добавления в него данных.

  • 0
    Я использую обработчик исключений зависимости, и исключения из всех классов направляются в него. Обработчик классифицирует исключения как простительные, непростительные, допустимые и т. Д. И выполняет всю запись в журнал.
  • 0
    @GayotFow, можете ли вы дать мне более подробную информацию о реализации (возможно, в качестве ответа на этот вопрос).
Показать ещё 2 комментария
Теги:
exception-handling
design

4 ответа

2

Если вы открыты для добавления нового метода, такого как ToLogString(), в качестве метода расширения для типа Exception, который мог бы объединить по умолчанию ToString() с материалами из Exception.Data.

1

Я бы порекомендовал вам определить набор широкого корпуса и, в некоторой степени, более тонкие подробные исключения, которые, как вы знаете, могут бросить вашу библиотеку. Это будут исключения, которые запрещают вашей библиотеке соответствовать определенным ожиданиям (в пределах вашего контроля), даже если исключение выбрано из-за неправильного использования в части пользователей.

Например, отсутствие нулевых значений. Поскольку вы не всегда можете принуждать пользователей вашей библиотеки следовать правилам, которые вы выкладываете, бросайте то, что естественно. throw new ArgumentNullException("Some message") или выбросить new MyLibraryArgumentNullException().

В некоторых случаях вы можете ввести набор пользовательских исключений, таких как throw new MyLibraryCantDoThisBecauseOfThatException().... Ты понимаешь мой смысл.

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

public SomeObject SomeProcess(AnotherObject anotherObject){
    if(anotherObject==null) throw ArgumentNullException();
    if(anotherObject.MustBePositive<=0) throw ArgumentException("x must be positive");
    if(_someDepenedencyMyLibaryCreates.NotThere) throw new MyLibraryMissingDepencyException()

    NowIHaveEnoughInfoToDoMyJobWithNoTry(); 
}

Следуя этим рекомендациям по пути, который ваша библиотека должна проверить и выбросить все исключения, которые не позволили бы ему выполнить свою задачу в вашей саранче контроля. Если у вас возникнут проблемы с памятью и т.д., Я бы позволил этим людям естественным образом вернуться из вашей библиотеки, потому что вы выполнили свою сделку. Пользователь должен получить достаточную информацию из вашего исключения, чтобы его можно было легко отследить без специального кольца декодера.

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

Теперь есть оговорки к этому... такие как исключения или исключения базы данных в коде бизнес-типа, которые могут выявить уязвимые внутренние компоненты вашей системы. В таких ситуациях вам может потребоваться обернуть или проверить конкретное исключение исключительной ситуации в бизнес-классе или базу данных, регистрацию оригинала и возврат исключения SomthingBadHappened с помощью указателя или некоторую ссылку на исключение, которое вы зарегистрировали.

Еще один краевой случай - это библиотеки веб-сервисов, которые могут полагаться на определенный код ответа HTTP. Для этого я бы посмотрел на Exception Shielding.

  • 0
    Я думаю, что это очень хороший ответ. Я согласен с вами, обычно проверяют все входные данные и генерируют соответствующие исключения (и, как вы говорите, остальным исключениям не требуется дополнительная информация, поскольку они являются либо системными проблемами, либо ошибками в моем коде). Я также учел это в своем дизайне. В любом случае, я обновил свой вопрос, чтобы объяснить, почему я хотел бы избежать явной проверки входных данных, если это возможно.
1

Некоторые мысли:

  1. Если ваша библиотека добавляет дополнительную информацию в исключения, тогда ваша будет единственной библиотекой, которая сделает это. Все ваши пользователи должны будут узнать, как получить дополнительную информацию.
  2. Тот факт, что большинство библиотек не делает ничего подобного, должен быть для вас намеком - либо это не было необходимо, либо было не полезно, либо они уже сделали бы это. .NET существует уже 12 лет. Вы должны спросить себя, почему это колесо еще не было изобретено.
  3. Прежде чем делать что-либо особенное с исключениями, убедитесь, что ваши специальные функции будут фактически использоваться. Особые функции должны быть требованием вашей библиотеки в комплекте с критериями приемки и приемочными испытаниями.

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

PS О некоторых интересных идеях по регистрации вы найдете в блоке приложений семантического журнала. Даже если вы не используете, идеи интересны.

  • 0
    Можно ли иметь единую и предсказуемую стратегию обработки исключений? Я согласен с частью о том, что не нужно добавлять новую информацию, но в большинстве крупных приложений, над которыми я работал, есть политика ведения журналов и обработки исключений, чтобы все стало неуправляемым.
  • 2
    В большинстве случаев единой и предсказуемой стратегией должно быть «не обрабатывать исключения». Затем вы проверяете, когда это может привести к тому, что ваше приложение не будет соответствовать его требованиям. Затем вы начинаете добавлять достаточно обработки исключений, чтобы соответствовать требованиям как можно позже. Вы обнаружите, что для обработки исключений гораздо меньше, чем вы могли предположить.
Показать ещё 8 комментариев
0

Вы имеете в виду что-то вроде этого?

namespace YourLibrary
{
   class Example
   {
       static void Main()
       {
            int [] v = null;
            try
            {
                v[1] = 10;
            }
            catch(Exception e)
            {
               throw new MyException(e);
            }
        }
    }

    public class MyException : Exception
    {        
       public MyException(Exception e):base(e.GetType().ToString() + e.Message)
       {            
       }
    }
}

Поступая таким образом, вы включаете информацию из предыдущего исключения в свой новый... Вы можете вставить e.GetType(). ToString() где-то внутри e.Message тоже, если вы хотите... но так как свойство Message is readonly вам необходимо передать код для форматирования в этом базовом вызове

редактировать

Я новичок и для С#, и для исключений, поэтому... Когда я увидел ваш вопрос, я начал пробовать кое-что здесь, и кажется, что сообщение консоли, которое вы получаете, когда генерируется исключение, - это то, что находится внутри свойства Message... и это свойство задается при передаче строки в конструкторе и не может быть изменено с момента его чтения, поэтому я думаю, что это решит вашу проблему

Ещё вопросы

Сообщество Overcoder
Наверх
Меню