Это хорошее использование ExtensionMethod? - PullRequest
10 голосов
/ 11 февраля 2009

Я только что написал оператор if в строках

if (value == value1 || value == value2 || value == value3 || value == value4)
    //do something

и меня раздражает, что мне всегда приходится повторять часть 'value =='. По моему мнению, это не служит никакой иной цели, кроме затруднения чтения.

Я написал следующий ExtensionMethod, который должен сделать описанный выше сценарий более читабельным:

public static bool IsEqualToAny<T>(this T value, params T[] objects)
{
    return objects.Contains(value);
}

Теперь я могу просто написать

if (value.IsEqualToAny(value1, value2, value3, value4))
    //do something

Это хорошее использование ExtensionMethod?

EDIT:

Спасибо за все великолепные ответы. Для справки: я сохранил метод. Хотя предположение о том, что вы могли бы просто использовать new []{value1,value2,value3,value4}.Contains(value), верно, я просто предпочитаю читать этот тип оператора if слева направо (, если это значение равно любому из этих вместо , если эти значения содержат это значение ). Для меня не проблема иметь еще один метод в intellisense для каждого объекта.

Ответы [ 8 ]

5 голосов
/ 11 февраля 2009

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

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

Синтаксис инициализатора массива C # 3 может быть проще?

bool isTrue = new[] { 1, 2, 3 }.Contains(3);

Конечно, для больших наборов данных вы можете захотеть куда-нибудь кешировать HashSet<T>; -p

4 голосов
/ 11 февраля 2009

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

Ответ "Да, это так"

1 голос
/ 11 февраля 2009

Вы действительно намереваетесь сделать Содержит и гарантировать, что вы будете применять Содержит на все возможные объекты , где вы можете использовать этот метод расширения?

Если некоторые данные объекты проверяют равенство с помощью перегрузки оператора ==, тогда ваше общее решение не будет выполнено. Это делает его не истинным эквивалентом множества тестов ==. Это также хороший пример опасности написания методов расширения!

Следующий код Linq работает, когда вы реализуете перегрузку операторов, а также если вы используете значение сравнения по умолчанию == для сравнения ссылок на объекты, чтобы сказать, что значение на самом деле является тем же объектом, что и значение1, 2, 3 или 4, учитывая как тип объекта ваших значений в данном конкретном случае:

V[] lv = { value, value2, value3, value4 };
if (lv.Any( v => v==value))
   // do something

Или сокращенная версия:

if (new List<V>{value, value2, value3, value4 }.Any( v => v==value))
   // do something

Мне не удалось заставить вышеприведенные лямбда-выражения работать в общем методе расширения.

В качестве хорошего (если не относящегося к делу) примера того, что я считаю прекрасным читабельным синтаксисом, идиома в Python будет выглядеть следующим образом:

if value in (value1, value2, value3, value4):
1 голос
/ 11 февраля 2009

Я бы сделал статический класс для этой цели. Мне не нравится это решение, потому что оно добавляет метод ко всем классам, что кажется немного излишним. Однако в некотором роде это происходит с OOD, потому что вы просите объекты выполнять функции над собой (вроде).

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

if (ConditionHelper.IsEqualToAny(value, value1, value2, value3)) 
{
    // Do something
}

Выполняет ту же работу и ничего не загрязняет.

1 голос
/ 11 февраля 2009

Вы также можете использовать синтаксис метода LINQ для этой задачи (используя пространство имен System.Linq):

            object[] objects = new object[10];
        objects.Contains(new MyClass());

Хм, позвольте мне подумать ... О, вы уже используете это. Но вы поместили его в отдельный метод вместо прямого вызова.

1 голос
/ 11 февраля 2009

Это кажется довольно справедливым, но я бы сделал шаг назад. Можете ли вы выразить какое-либо деловое значение в сравнении? Каковы эти ценности? Возможно, вам лучше использовать метод с именем IsSpecialCustomerLocation или что-то, что выражает реальное намерение кода.

1 голос
/ 11 февраля 2009

выглядит хорошо для меня, хотя кажется немного нетрадиционным

0 голосов
/ 18 мая 2009

Если вы проверяете только значение Enum (как вы сказали в комментарии к ответу Роджерса), вы должны использовать FlagsAttribute в Enum.

[Flags]
public enum Value
{
  Value1 = 0,
  Value2 = 1,
  Value3 = 2,
  Value4 = 4
}

Value value = Value.Value1;
if (value | Value.Value1 | Value.Value2 | Value.Value3 | Value.Value4)
{
  // You can also use other bitwise operations, like & (AND), ^ (XOR) and ~ (NOT)
}

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

...