Рекомендую к прочтению статьи об исключениях в .NET. Точно стоит прочитать первую статью — Исключения: архитектура системы типов.
В ней много полезного, особенно — для новичков. Остальные тоже можно, если эта тема интересует:
Если же времени на чтение не хватает, полезные мысли из первой статьи:
Хорошая практика — объявлять классы для исключений в том же namespace, что и код, их бросающий.
Думайте о зоне отвественности, когда делаете классы для исключений. Иногда лучше обработать “низкоуровневое” исключение, выбросив более соотвествующее.
Логично пользоваться схемой наследования исключений на примере ArgumentException, от которого наследуются более специфичные.