C # In () метод? (как Sql)

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

Я думаю, что мы все использовали это:

select someThing from someTable where someColumn in('item1', 'item2')

В C # я должен написать что-то вроде этого:

if (someEnum == someEnum.Enum1 || someEnum == someEnum.Enum2 || 
  someEnum == someEnum.Enum3)
{
  this.DoSomething();
}

Это работает, но это просто многословно.

Из-за разочарования я написал метод расширения, чтобы выполнить то, что я пытаюсь сделать.

namespace System
{
    public static class SystemExtensions
    {
        public static bool In<T>(this T needle, params T[] haystack)
        {
            return haystack.Contains(needle);
        }
    }
}

Теперь я могу написать более короткий код:

if (someEnum.In(someEnum.Enum1, someEnum.Enum2, someEnum.Enum3))
  this.DoSomething();
if (someInt.In(CONSTANT1, CONSTANT2))
  this.DoSomethingElse();

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

Любая помощь, которую вы можете предложить, была бы отличной, Спасибо

РЕДАКТИРОВАТЬ: Спасибо всем за глубокий анализ. Я думаю, что я буду продолжать использовать мой метод In ().

19
задан Robert H. 9 August 2010 в 16:23
поделиться

8 ответов

Нет существующего метода расширения, подобного тому, который есть у вас. Позвольте мне объяснить, почему я так думаю (помимо очевидной причины, «потому что она не была указана, реализована, протестирована, задокументирована и т. Д.»).

По сути, такая реализация обязательно неэффективна. Создание массива из параметров, переданных в В (как это происходит, когда вы используете ключевое слово params ), является операцией O (N) и вызывает неоправданное давление сборщика мусора (из-за создания нового T [] объект). Содержит , затем выполняет перечисление по этому массиву, что означает, что время выполнения исходного кода было увеличено более чем вдвое (вместо одного частичного перечисления с помощью короткозамкнутой оценки у вас есть одно полное перечисление, за которым следует частичное перечисление ).

Давление GC, вызванное конструкцией массива , можно несколько уменьшить, заменив версию метода расширения params на X-перегрузки, принимающие от 1 до X параметров типа T , где X - некоторое разумное число ... например, 1-2 дюжины. Но это не меняет того факта, что вы передаете значения X на новый уровень стека вызовов только для проверки потенциально меньшего, чем X из них (т.е. это не устраняет снижение производительности, а только снижает его).

И есть еще одна проблема: если вы хотите, чтобы этот метод расширения В служил заменой связке связанных || сравнений, есть еще кое-что, что вы могли упустить из виду . С помощью || вы получаете краткую оценку; то же самое не относится к параметрам, передаваемым методам. В случае перечисления, как в вашем примере, это не имеет значения. Но рассмотрите этот код:

if (0 == array.Length || 0 == array[0].Length || 0 == array[0][0].Length)
{
    // One of the arrays is empty.
}

Приведенный выше (странный / плохой - только для иллюстрации) код не должен вызывать исключение IndexOutOfRangeException (он может вызывать исключение NullReferenceException , но это не имеет отношения к точку я делаю). Однако «эквивалентный» код, использующий In , вполне может:

if (0.In(array.Length, array[0].Length, array[0][0].Length)
{
    // This code will only be reached if array[0][0].Length == 0;
    // otherwise an exception will be thrown.
}

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

7
ответ дан 30 November 2019 в 05:16
поделиться

Думаю, вы уже близки к использованию вызова Contains .

List<strong> items = List<string>{ "item1", "item2", "item3" };
bool containsItem = items.Contains( "item2" );

Это общий подход для запросов Linq.

from item in ...
where items.contains( item )
select item

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

1
ответ дан 30 November 2019 в 05:16
поделиться

Больше я ничего не знаю.

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

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

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

1
ответ дан 30 November 2019 в 05:16
поделиться

Вот и все. Ваш метод расширения In () очень хорош. Даже если вы используете LINQ, который смоделирован на основе SQL, вам все равно придется использовать Contains для указания использования IN в SQL.

from a in table
where SomeArray.Contains(a.id)
select a;

Переводится на:

select * from table a where a.id in (.....)
1
ответ дан 30 November 2019 в 05:16
поделиться

Возможно, вас заинтересует FlagAttibute , если вы хотите сделать это, в частности, с помощью Enums.

0
ответ дан 30 November 2019 в 05:16
поделиться

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

0
ответ дан 30 November 2019 в 05:16
поделиться

Языки не могут понравиться всем, но делаете ли вы это, или компилятор делает это, особой разницы нет. Этот язык дает вам Any & Contains

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

0
ответ дан 30 November 2019 в 05:16
поделиться

Вы можете использовать метод расширения .Intersect, если хотите, чтобы возвращались отдельные значения. Например.

List<string> test = new List<string>() { "1", "2", "2", "3" };
List<string> test2 = new List<string>() { "1", "2" };

var results = test.Intersect<string>(test2);
0
ответ дан 30 November 2019 в 05:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: