Подтвердить что ты не робот

Метод С# In()? (например, Sql)

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

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

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

В С# мне приходится писать такие вещи:

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();

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

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

EDIT: Спасибо всем за глубокий аналсис. Я думаю, что продолжу использовать метод In().

4b9b3361

Ответ 1

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

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

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

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

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 - плохая. В большинстве случаев, когда он используется правильно, он может сэкономить при наборе текста, а стоимость производительности/памяти не будет заметна. Я просто предлагаю свои мысли о том, почему метод такого типа не подходит в качестве встроенного метода библиотеки: поскольку его издержки и ограничения, вероятно, будут неправильно истолкованы, что приведет к чрезмерному использованию и субоптимальному коду.

Ответ 2

Я думаю, что вы близко используете вызов Contains.

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

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

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

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

Ответ 3

Это в значительной степени. Ваш метод расширения 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 (.....)

Ответ 4

Я ничего не знаю.

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

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

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

Ответ 5

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

Ответ 6

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

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

Ответ 7

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

Ответ 8

Вы можете использовать метод расширения .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);