C# — более удобный способ сравнить одно значение с несколькими значениями в одной строке кода

У меня есть этот фрагмент кода:

if (filter != RECENT &&
    filter != TODAY &&
    filter != WEEK &&
    filter != MONTH &&
    filter != ALLTIME)
{
    filter = RECENT;
}

Обратите внимание, что filter является string и сравнивается с const string типами. Есть ли способ сделать это встроенным и сделать его более читаемым? Выполнение этого с тернарным оператором не делает его намного лучше, так как мне все еще нужно повторить filter != XXXXX

filter = filter != RECENT &&
         filter != TODAY &&
         filter != WEEK &&
         filter != MONTH &&
         filter != ALLTIME ? RECENT : filter;

а это явно не работает

filter = filter != RECENT && TODAY && WEEK && MONTH && ALLTIME ? RECENT : filter;

Есть ли более красивый способ (красивее == вся логика должна быть в одной строке кода) для этого сравнения? Точнее, чтобы предотвратить filter != XXXXX повторение.

Обратите внимание, что производительность не является моей главной задачей в этом вопросе.


person Boško Bezik    schedule 27.10.2018    source источник
comment
Зависит от того, что на самом деле Filter. Это перечисление? Если да, то это перечисление с атрибутом [Flags]?   -  person    schedule 27.10.2018
comment
@elgonzo filter всего лишь string. Он сравнивается с константами, например. const string RECENT = "recent";.   -  person Boško Bezik    schedule 27.10.2018
comment
Возможно, вы могли бы поместить эти строки в массив и использовать Linq. Если вы затем создадите/используете статический метод - или, лучше, метод расширения - с аргументом params string[] ... (аргументом params string[] будет массив строк, о котором я говорил), вы можете упростить тестирование до чего-то вроде filter.IsNot(Filter.RECENT, Filter.TODAY, ...)   -  person    schedule 27.10.2018
comment
Создайте массив ваших констант, а затем !array.Contains(filter) или рассмотрите возможность использования перечисления, как предложил elgonzo. Мы не знаем вашего приложения, но из того, что мы знаем, это может быть лучше, чем сравнение строк.   -  person just-my-name    schedule 27.10.2018
comment
Правда, предложение Linq в этом сценарии может быть немного излишним; функции, предоставляемые типом массива (например, Contains), могут быть всем, что вам нужно...   -  person    schedule 27.10.2018
comment
@just-my-name filter — это string параметр, передаваемый методу. Создание перечислений создало бы мне больше работы. Я использовал ваше решение ...Contains(filter)..., и оно прекрасно работает.   -  person Boško Bezik    schedule 27.10.2018
comment
И почему встроенный текст более удобочитаем? Что не так с читабельностью текущего решения? Действительно ли это стоит «оптимизировать» каким-либо образом, основываясь на явно самоуверенной эстетике кода? Единственной проблемой может быть повторение кода, но это легко решается.   -  person InBetween    schedule 27.10.2018
comment
@just-my-name Пожалуйста, ответьте на мой вопрос, так как ваш комментарий решил мою проблему. Я выберу его в качестве ответа и проголосую за вас. filter = new[]{RECENT, TODAY, WEEK, MONTH, ALLTIME}.Contains(filter) ? filter : RECENT; решил мою проблему.   -  person Boško Bezik    schedule 27.10.2018
comment
Возможный дубликат сравнения нескольких строк с C#   -  person mjwills    schedule 27.10.2018


Ответы (2)


Я предпочитаю создать метод расширения.

  public static bool NotIn(this string filter , params string[] valuesToCompare)
    {
        var result = true;
        foreach (var item in valuesToCompare)
        {
            if (filter == item) return false;
        }
        return result;
    }

и использовать как

if( filter.NotIn("RECENT", "TODAY ", "WEEK ", "MONTH", "ALLTIME"))
  {
     filter = "RECENT";
  }
person Gaurav Moolani    schedule 27.10.2018
comment
Недостатком этого подхода является создание массива при каждом вызове. - person mjwills; 27.10.2018
comment
Кроме того, foreach можно заменить на Contains. - person mjwills; 27.10.2018

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

Использование хэш-набора

Сравнение с учетом регистра:

var filters = new HashSet<string>(new[] { RECENT, TODAY, WEEK, MONTH, ALLTIME });

if (!filters.Contains(filter))
{
    filter = RECENT;
}

Сравнение без учета регистра:

var filters = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
filters.UnionWith(new[] { RECENT, TODAY, WEEK, MONTH, ALLTIME });

if (!filters.Contains(filter))
{
    filter = RECENT;
}

Использование массива строк

Сравнение с учетом регистра:

string[] filters = {RECENT, TODAY, WEEK, MONTH, ALLTIME};

if (!filters.Contains(filter))
{
    filter = RECENT;
}

Сравнение без учета регистра:

string[] filters = {RECENT, TODAY, WEEK, MONTH, ALLTIME};

if (!filters.Contains(filter, StringComparer.OrdinalIgnoreCase))
{
    filter = RECENT;
}

РЕДАКТИРОВАТЬ

Тернарный оператор ?: можно было бы использовать вместо оператора if, но IMO это сделало бы код менее читаемым. Кроме того, с точки зрения отладки проще установить точку останова внутри оператора if, чтобы проверить, содержит ли массив фильтр, чем устанавливать точку останова с помощью оператора ?::

Точки останова

person Rui Jarimba    schedule 27.10.2018