Какова лучшая практика для проверки параметров конструктора?
Предположим, что немного C #:
public class MyClass
{
public MyClass(string text)
{
if (String.IsNullOrEmpty(text))
throw new ArgumentException("Text cannot be empty");
// continue with normal construction
}
}
Было бы приемлемо бросить исключение?
Альтернативой, с которой я столкнулся, была предварительная проверка перед созданием экземпляра:
public class CallingClass
{
public MyClass MakeMyClass(string text)
{
if (String.IsNullOrEmpty(text))
{
MessageBox.Show("Text cannot be empty");
return null;
}
else
{
return new MyClass(text);
}
}
}
c#
validation
constructors
MPelletier
источник
источник
Ответы:
Я склонен выполнять все мои проверки в конструкторе. Это необходимо, потому что я почти всегда создаю неизменные объекты. Для вашего конкретного случая я думаю, что это приемлемо.
Если вы используете .NET 4, вы можете сделать это. Конечно, это зависит от того, считаете ли вы строку, содержащую только пробел, недействительной.
источник
Init
чтобы получить какой-то код ошибки, когда исключение будет работать так же хорошо и заставлять ваш объект всегда поддерживать действительное состояние?ArgumentNullException
а другое проверяет пустое и бросаетArgumentException
. Позволяет вызывающему быть более разборчивым, если он хочет в обработке исключений.Многие люди утверждают, что конструкторы не должны бросать исключения. Например, KyleG на этой странице делает именно это. Честно говоря, я не могу придумать причину, почему нет.
В C ++ выбрасывать исключение из конструктора - плохая идея, потому что он оставляет вам выделенную память, содержащую неинициализированный объект, на который у вас нет ссылок (т.е. это классическая утечка памяти). Вероятно, отсюда и возникает стигма - куча разработчиков старой школы на C ++ наполовину отучились от обучения C # и просто применили к нему то, что знали из C ++. Напротив, в Objective-C Apple отделяла этап выделения от этапа инициализации, поэтому конструкторы на этом языке могут генерировать исключения.
C # не может пропустить память из неудачного вызова конструктора. Даже некоторые классы в .NET Framework будут генерировать исключения в своих конструкторах.
источник
Бросить исключение IFF, класс не может быть приведен в согласованное состояние в отношении его семантического использования. В противном случае нет. НИКОГДА не позволяйте объекту существовать в несогласованном состоянии. Это включает в себя не предоставление полных конструкторов (например, наличие пустого конструктора + initialize () до того, как ваш объект фактически полностью построен) ... ПРОСТО СКАЗАТЬ НЕТ!
В крайнем случае, все это делают. Я сделал это на днях для очень узко используемого объекта в ограниченном объеме. Однажды в будущем я или кто-то другой, вероятно, заплатит цену за этот промах на практике.
Я должен отметить, что под «конструктором» я подразумеваю то, что клиент вызывает для создания объекта. Это также может быть что-то иное, чем реальная конструкция, которая называется «Конструктор». Например, что-то подобное в C ++ не будет нарушать принцип IMNSHO:
Поскольку единственный способ создать это
funky_object
- вызватьbuild_funky
принцип, согласно которому недопустимый недопустимый объект остается неизменным, даже если фактический «Конструктор» не завершает работу.Это много дополнительной работы, хотя для сомнительной выгоды (возможно, даже потери). Я все еще предпочел бы маршрут исключения.
источник
В этом случае я бы использовал фабричный метод. По сути, у вашего класса есть только частные конструкторы и есть фабричный метод, который возвращает экземпляр вашего объекта. Если начальные параметры недействительны, просто верните null и попросите вызывающий код решить, что делать.
Никогда не бросайте исключения, если условия не являются исключительными. Я думаю, что в этом случае пустое значение можно легко передать. В этом случае использование этого шаблона позволит избежать исключений и снижения производительности, которые они несут при сохранении действительного состояния MyClass.
источник
Можно разумно поставить под сомнение эти рекомендации и сказать: «Но я не следую этим правилам, и мой код работает нормально!» На это я бы ответил: «Ну, это может быть правдой, пока это не так».
источник
Это зависит от того, что делает MyClass. Если MyClass на самом деле был классом хранилища данных, а текст параметра - строкой соединения, то лучше всего было бы генерировать исключение ArgumentException. Однако, если MyClass является классом StringBuilder (например), вы можете просто оставить его пустым.
Так что это зависит от того, насколько важен текст параметра для метода - имеет ли объект смысл с нулевым или пустым значением?
источник
Я предпочитаю установить значение по умолчанию, но я знаю, что в Java есть библиотека «Apache Commons», которая делает что-то подобное, и я думаю, что это тоже довольно хорошая идея. Я не вижу проблемы с выдачей исключения, если недопустимое значение приведет объект в непригодное для использования состояние; строка не хороший пример, но что, если она была для DI бедного человека? Вы не можете работать, если
null
вместоICustomerRepository
интерфейса , скажем, передано значение . Я бы сказал, что в такой ситуации исключение является правильным способом обработки вещей.источник
Когда я работал в C ++, я не использовал генерацию исключений в конструкторе из-за проблемы утечки памяти, к которой это может привести, я научился этому нелегко. Любой, кто работает с c ++, знает, насколько сложной и проблемной может быть утечка памяти.
Но если вы находитесь в C # / Java, то у вас нет этой проблемы, потому что сборщик мусора будет собирать память. Если вы используете C #, я думаю, что лучше использовать свойство для удобного и согласованного способа убедиться, что ограничения данных гарантированы.
источник
Бросок исключения станет настоящей болью для пользователей вашего класса. Если проверка является проблемой, то я обычно делаю создание объекта в два этапа.
1 - Создать экземпляр
2 - Вызвать метод Initialize с возвращаемым результатом.
ИЛИ
Вызовите метод / функцию, которая создаст для вас класс, который может выполнить проверку.
ИЛИ
У меня есть флаг isValid, который мне не особенно нравится, но некоторые люди делают.
источник
isValid = false
. Необходимость проверки после того, как класс создан, ужасен, очень подвержен ошибкам дизайн. И, как вы сказали, есть конструктор, затем вызовите initialize ... Что если я не вызову initialize? Что тогда? А что, если Initialize получит неверные данные, могу ли я выдать исключение сейчас? Ваш класс не должен быть сложным в использовании.