Почему myString.IsNullOrEmpty() не встроен в .Net?
Немного академический вопрос, но я пытаюсь понять структуру фреймворка на более глубоком уровне.
Итак, мы имеем String.IsNullOrEmpty(MyString)
и мы могли бы написать метод расширения, чтобы включить myString.IsNullOrEmpty()
, хотя это, возможно, не самая большая идея. Смотрите: Расширяет класс String с запуском IsNullOrEmpty?.
Итак, мой вопрос: почему MS не пишет эту функциональность как часть .Net framework? Есть ли какая-то оценка эффективности? И в более общем плане, почему любой метод или свойство, которые считаются достаточно ценными для построения, доступные через объект String, не могут быть доступны как член любого объекта типа строки?
Ответы
Ответ 1
Статический метод String.IsNullOrEmpty
был введен в .NET Framework версии 2.0. Методы расширения были внедрены в .NET Framework версии 3.5 вместе с LINQ. Поэтому у Microsoft не было этой опции при введении IsNullOrEmpty
.
Конечно, IsNullOrEmpty
не может быть методом экземпляра String
, так как вы не можете вызвать метод для ссылки, которая null
. Однако вы можете вызвать метод расширения для такой ссылки, поскольку синтаксис метода расширения - это просто синтаксический сахар для вызова статического метода.
Предположим, что IsNullOrEmpty
был методом расширения. Тогда вы можете назвать это следующим образом:
string s = null;
bool result = s.IsNullOrEmpty();
В комментарии кто-то притворяется, что этот вызов вызовет NullReferenceException
. Метод расширения будет объявлен следующим образом:
public static class StringExtensions
{
public static bool IsNullOrEmpty(this string s)
{
return s == null || s.Length == 0;
}
}
... и будет использоваться так...
string s = null;
bool result = s.IsNullOrEmpty();
... который является просто синтаксическим сахаром для...
string s = null;
bool result = StringExtensions.IsNullOrEmpty(s);
... и, таким образом, не будет генерировать исключение. Является ли это хорошей идеей или нет, это другой вопрос (см. ответ, предоставленный usr ниже).
Ответ 2
Как правило, считается неправильной практикой, чтобы метод расширения не прерывался при вызове в null
ссылке. Это связано с тем, что просто прочитав код, вы не можете сказать, что вызывается метод расширения. Ваша интуиция будет заключаться в том, чтобы вызвать вызов ((string)null).IsNullOrEmpty()
.
Очевидно, что такой метод не был бы возможен как метод экземпляра. Итак, мы нарушаем интуицию здесь.
Тем не менее, я точно определил это расширение во всех важных моих проектах и во многих случаях вопиюще полезен. Я готов принять этот небольшой уровень нечистоты и неинтуитивности.
Авторы каркаса явно не согласились. Я также думаю, что этот метод не должен входить в .NET Framework, потому что он является своего рода "продвинутым" и препятствует обучаемости. Новичок может спросить: "Да? Иногда я могу безопасно ссылаться на нулевую ссылку, иногда я не могу? Как сказать, когда?".
Ответ 3
Потому что, если вы могли бы использовать IsNullOrEmpty()
в нулевой строке, возможно, вам захочется переименовать метод в IsEmpty()
.
Шутки в стороне, так реализуется метод:
public static bool IsNullOrEmpty(string value)
{
if (value != null)
return value.Length == 0;
else
return true;
}
Ясно, что условие всегда будет истинным в случае строковых экземпляров.
Кроме того, одна маленькая деталь. Возьмем, например, string.Concat
, который является статическим методом. Было бы разумным, например, удивляться, почему нет метода относительного экземпляра; взглянув на его реализацию, я считаю, что они хотели сделать эти методы максимально возможными. При передаче аргументов методу в случае нулевых ссылок они заменяются пустыми строками, а не имеют исключения. Это может быть полезно, когда вы не знаете заранее, если ваша строка (-ы) действительно будет содержать значение или будет равна null, и я предполагаю, что разработчики фреймворков решили, что было бы лучше внести вклад в чтение кода путем обработки нулевых строк как пустые и сохраняя конечный пользователь дополнительной проверкой. Разумеется, если string.Concat
был методом экземпляра (или, по крайней мере, имел альтернативу), пользователь все равно мог передавать нулевые аргументы, но используемый экземпляр обязательно будет недействительным.