Расширяет ли класс String IsNullOrEmpty запутанным? - программирование
Подтвердить что ты не робот

Расширяет ли класс String IsNullOrEmpty запутанным?

Все знают и любят метод String.IsNullOrEmpty(yourString).

Мне было интересно, не собирается ли запутать разработчиков или сделать код лучше, если мы добавим класс String, чтобы иметь такой метод:

yourString.IsNullOrEmpty();

Pro:

  • Более читаемый.
  • Меньше набрав.

Минусы:

  • Может быть запутанным, потому что yourString переменная может быть null, и она выглядит как вы выполняете метод на null.

Как вы думаете?

Тот же вопрос можно задать по методу myObject.IsNull().

Вот как я его написал:

public static class StringExt
{
  public static bool IsNullOrEmpty(this string text)
  {
    return string.IsNullOrEmpty(text);
  }

  public static bool IsNull(this object obj)
  {
    return obj == null;
  }
}
4b9b3361

Ответ 1

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

Следствие этой проблемы существует в С++. В нескольких реализациях С++ можно вызвать методы экземпляра на указателях NULL, если вы не касаетесь каких-либо полей или виртуальных методов в типе. Я работал с несколькими фрагментами кода, которые делают это намеренно, и дают методы по-разному, когда "this==NULL". Это сходит с ума от работы.

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

  • Рассматривайте реальную реализацию метода, как если бы это был еще один статический метод, потому что это на самом деле. Например, исключение ArgumentException вместо исключения NullReference для null this
  • Не позволяйте методу расширения выполнять трюки, которые не мог выполнить обычный метод экземпляра

РЕДАКТИРОВАТЬ Ответ на комментарий Мехрдада

Проблема с его использованием заключается в том, что я не вижу str.IsNullOrEmpty как имеющего значительное функциональное преимущество перед String.IsNullOrEmpty(str). Единственное преимущество, которое я вижу, - это то, что нужно набирать меньше текста, чем другое. То же самое можно сказать и о методах расширения. Но в этом случае вы дополнительно изменяете то, как люди думают о потоке программы.

Если более короткая типизация - это то, что действительно хотят люди, не будет IsNullOrEmpty (str) намного лучше? Он однозначен и является самым коротким. Сегодня True С# не поддерживает такую ​​функцию. Но представьте, если бы в С# я мог сказать

using SomeNamespace.SomeStaticClass;

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

Ответ 2

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

Позвольте мне противопоставить свои аргументы.

Я не верю, что ВСЕ, что вызов метода на объекте, который может быть пустым, путают. Дело в том, что мы проверяем только нули в определенных местах, а не в 100% случаев. Это означает, что есть процент времени, когда каждый вызов метода, который мы делаем, потенциально имеет нулевой объект. Это понятно и приемлемо. Если это не так, мы будем проверять значение null перед каждым вызовом метода.

Итак, как это сбивает с толку, что вызов определенного метода может происходить на нулевом объекте? Посмотрите на следующий код:

var bar = foo.DoSomethingResultingInBar();
Console.Writeline(bar.ToStringOr("[null]"));

Вы смущены? Вы должны быть. Потому что здесь реализация foo:

public Bar DoSomethingResultingInBar()
{
  return null; //LOL SUCKER!
}

См? Вы читаете образец кода, не путаясь вообще. Вы поняли, что, возможно, foo вернет null из этого вызова метода, а вызов ToStringOr на bar приведет к NRE. Твоя голова закружилась? Конечно нет. Его понимали, что это может произойти. Теперь этот метод ToStringOr не знаком. Что вы делаете в этих ситуациях? Вы либо читаете документы в методе, либо просматриваете код вызова. Вот он:

public static class BarExtensions
{
  public static string ToStringOr(this bar, string whenNull)
  {
    return bar == null ? whenNull ?? "[null]" : bar.ToString();
  }
}

Непонятный? Конечно нет. Очевидно, что разработчику нужен сокращенный метод проверки того, является ли bar null и заменяет для него ненулевую строку. Это может значительно сократить ваш код и повысить читаемость и повторное использование кода. Конечно, вы могли бы сделать это другими способами, но этот путь не был бы более запутанным, чем любой другой. Например:

var bar = foo.DoSomethingResultingInBar();
Console.Writeline(ToStringOr(bar, "[null]"));

Когда вы сталкиваетесь с этим кодом, что у вас есть по-другому, чем в оригинальной версии? Вы все еще должны изучить код, вам все равно придется определять его поведение, когда bar равно null. Вам все равно придется иметь дело с этой возможностью.

Сложны ли методы расширения? Только если вы их не понимаете. И, честно говоря, то же самое можно сказать о ЛЮБОЙ части языка, от делегатов до лямбда.

Ответ 3

Я думаю, что корень этой проблемы заключается в том, что Джон Скит упомянул в списке вещей, которые он ненавидит на своем любимом языке (С#): С# не должен импортировать все методы расширения во всем пространстве имен автоматически. Этот процесс должен быть сделан более явно.

Мое личное мнение об этом конкретном вопросе (так как мы ничего не можем сделать из этого факта) использовать, если хотите, метод расширения. Я не говорю, что это не будет путать, но этот факт о методах расширения (который может быть вызван ссылками null) является глобальной вещью и не влияет только на String.IsNullOrEmpty, поэтому разработчики С# должны ознакомиться с он.

Кстати, ему повезло, что Visual Studio четко идентифицирует методы расширения (extension) в подсказке IntelliSense.

Ответ 4

Мне очень нравится этот подход. AS LONG. Как метод дает понять, что он проверяет, что объект имеет значение null. ThrowIfNull, IsNull, IsNullOrEmpty и т.д. Это очень читаемо.

Ответ 5

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

Сказав все это, у меня есть расширение строки, которое проверяет не только, если строка является пустой или пустой, но также и содержит только пробелы. Я называю это IsNothing. Вы можете найти его here.

Ответ 6

Не похоже, что вы вызываете метод с нулевой переменной. Вы/вызываете/вызываете метод для нулевой переменной, хотя один реализован через статический метод расширения. Я не знал, что методы расширения (которые я уже осмелел) поддерживали это. Это даже позволяет вам делать сумасшедшие вещи, такие как:

public static int PowerLength(this string obj)
{
return obj == null ? 0 : obj.Length;
}

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

Ответ 7

Да, это смутит.

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

Возможно, для кого-то нового для .NET этот метод расширения может быть проще справиться, но существует вероятность опасность, что он/она не понимает всех аспектов методов расширения (например, вы необходимо импортировать пространство имен и что он может быть вызван на null). Он/она может задаться вопросом, почему этот метод расширения не существует в другом проекте. В любом случае: даже если кто-то новичок в .NET, синтаксис метода IsNullOrEmpty() может стать естественным довольно быстрым. Также здесь преимущества методов расширения не будут приводить к уменьшению путаницы, вызванной им.

Edit: попытался перефразировать то, что я хотел сказать.

Ответ 8

Посмотрите на pro: s и con: s...

  • Более читаемый.

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

  1. Меньше набрав.

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

  • Может быть запутанным, потому что переменная yourString может быть нулевой и выглядит вы выполняете метод по нулевой переменной.

Правда, (как упоминалось выше).

Ответ 9

Я думаю, что расширение любого объекта с помощью вызова типа "IsNull" немного запутанно и его следует избегать, если это возможно.

Можно утверждать, что метод IsEmptyString может быть полезен для типа String, и это потому, что вы обычно комбинируете это с тестом на null, что IsNullOrEmpty может быть полезным, но я бы избегал этого тоже из-за того, что тип string уже имеет статический метод, который делает это, и я не уверен, что вы сберегаете себя, что много набираете (максимум 5 символов).

Ответ 10

Вызов метода для переменной с нулевым значением обычно приводит к исключению NullReferenceException. IsNullOrEmpty() -Method отклоняется от этого поведения способом, который не предсказуем, просто глядя на код. Поэтому я бы посоветовал не использовать его, поскольку он создает путаницу, и преимущество сохранения нескольких символов минимально.

Ответ 11

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

Ответ 12

При сравнении экземпляра класса с нулевым значением с использованием ".IsNull()" даже короче, чем использование "== null". Величины изменяются в общих классах, когда аргумент универсального типа без ограничения может быть типом значения. В этом случае сравнение с типом по умолчанию является длинным, и я использую расширение ниже:

    public static bool IsDefault<T>(this T x)
    {
        return EqualityComparer<T>.Default.Equals(x, default(T));
    }