Запутывает ли расширение класса String с IsNullOrEmpty? - PullRequest
11 голосов
/ 26 апреля 2009

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

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

yourString.IsNullOrEmpty();

Pro:

  1. Более читабельно.
  2. Меньше печатать.

Минусы:

  1. Может сбивать с толку, потому что 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;
  }
}

Ответы [ 12 ]

19 голосов
/ 26 апреля 2009

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

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

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

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

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

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

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

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

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

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

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

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

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

8 голосов
/ 26 апреля 2009

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

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

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

6 голосов
/ 26 апреля 2009

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

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

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

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

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

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

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

using SomeNamespace.SomeStaticClass;

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

5 голосов
/ 26 апреля 2009

Мне очень нравится этот подход КАК ДОЛГО, КАК метод дает понять, что он проверяет, что объект нулевой. ThrowIfNull, IsNull, IsNullOrEmpty и т. Д. Он очень удобочитаемый.

4 голосов
/ 26 апреля 2009

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

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

1 голос
/ 26 апреля 2009

Давайте посмотрим на плюсы и минусы: сек ...

  1. Более читабельно.

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

  1. Меньше печатать.

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

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

Верно, (как упомянуто выше).

1 голос
/ 26 апреля 2009

Да, это смущает.

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

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

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

1 голос
/ 26 апреля 2009

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

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

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

0 голосов
/ 09 июля 2014

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

    public static bool IsDefault<T>(this T x)
    {
        return EqualityComparer<T>.Default.Equals(x, default(T));
    }
0 голосов
/ 26 апреля 2009

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

...