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

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

19 голосов
/ 09 августа 2010

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

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

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

Ответы [ 8 ]

7 голосов
/ 09 августа 2010

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

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

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

1 голос
/ 09 августа 2010

Я больше ничего не знаю.

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

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

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

1 голос
/ 09 августа 2010

Вот и все. Ваш 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 голос
/ 09 августа 2010

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

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

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

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

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

0 голосов
/ 09 августа 2010

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

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

0 голосов
/ 09 августа 2010

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

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

0 голосов
/ 09 августа 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...