Правильное использование исключений .NET - PullRequest
4 голосов
/ 04 апреля 2010

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

Если, например, у меня есть класс: Альбом с коллекцией песен:

List<Song>

И метод в Альбом для добавления Песни :

public void AddSong(Song song)
{
    songs.Add(song);
}

Должен ли я выдать исключение, если пользователь пытается добавить песню, которая уже существует? Если да, то какой тип исключения?

Я слышал фразу: «Используйте исключения только в исключительных обстоятельствах», но я хочу сказать клиенту, реализующему Album, что именно пошло не так (не просто вернуть логическое значение).

Ответы [ 5 ]

5 голосов
/ 04 апреля 2010

В точно такой же ситуации дизайнеры .NET в Microsoft решили выбросить ArgumentException с описательным сообщением.Ох, и они были довольно последовательны в этом .

4 голосов
/ 04 апреля 2010

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

Делая это, вы не только избегаете написания метода поиска O (N) для проверки на наличие дубликатов, но также можете создать пузырек для ранее существовавшего исключения дубликата, которое будет генерировать коллекция такого рода. *

Однако .NET не имеет отдельной коллекции, которая сохраняет порядок сортировки, хотя очень просто расширить List для поддержки этого.

Подход, который я использовал ниже, жертвует объемом памяти для скорости, сохраняя уникальные значения во втором HashSet. Если бы объем памяти был более важным, вам просто нужно было бы проверять O (N) при каждой операции добавления. Поскольку методы не являются виртуальными (по некоторым причинам) в List, я привел к сокрытию базовых методов с помощью ключевого слова new.

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

    public class UniqueList<T> : List<T>
    {
        private HashSet<T> _internalHash = new HashSet<T>();

        public UniqueList() : base() { }
        public UniqueList(IEnumerable<T> collection) : base(collection) { }
        public UniqueList(int capacity) : base(capacity) { }

        public new void Add(T item)
        {
            if (!_internalHash.Add(item))
                throw new ArgumentException("Item already exists in UniqueList");

            base.Add(item);
        }

        public new void AddRange(IEnumerable<T> collection)
        {
            foreach (T t in collection)
            {
               this.Add(t);
            }
        }

        public new bool Remove(T item)
        {
            _internalHash.Remove(item);
            return base.Remove(item);               
        }

        public new int RemoveAll(Predicate<T> match)
        {
            int removedElems = 0;

            foreach (T item in this)
            {
                if (match(item))
                {
                    this.Remove(item);
                    removedElems++;
                }
            }

            return removedElems;
        }

        public new void RemoveAt(int index)
        {                
           this.Remove(this[index]);             
        }

        public new void RemoveRange(int index, int count)
        {
            for (int i = index; i < count; i++)
            {
                this.Remove(this[i]);
            }
        }
    }
3 голосов
/ 04 апреля 2010

Вместо генерации исключения вы можете заставить метод AddSong возвращать логическое значение - true, если песня успешно добавлена, и false в противном случае.Лично я думаю, что исключение было бы приемлемым в этом случае, если разумно ожидать, что песня является уникальной в коллекции.Например, если коллекция представляет собой список песен в альбоме, вы не должны ожидать дублирование песни (одинаковое название, одинаковая продолжительность, одинаковое положение в последовательности дорожек и т. Д.).У вас есть возможность создать собственный класс исключений, производный от System.Exception, для создания пользовательских ошибок, если вы хотите, чтобы вы могли выдать исключение, которое точно объясняет, почему произошла ошибка.

0 голосов
/ 04 апреля 2010

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

AlbumException

Затем, взяв из ответа CMerat, создайте.

DuplicateSongException

Это, конечно, должно наследоваться от AlbumException.

Лично я бы сделал класс Album неизменным. В этом случае вся эта ситуация исчезнет.

0 голосов
/ 04 апреля 2010

Вы всегда можете создавать свои собственные исключения. Просто создайте класс, который наследуется от Exception (или, в данном случае, ArgumentException).

Что-то вроде DuplicateItemException (или DuplicateSongException, если вы хотите что-то очень конкретное) звучит как правильно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...