C#In()方法? (比如Sql)

时间:2010-08-09 13:36:26

标签: c# .net enums

我觉得很难找到一个相当简单的方法。

我想我们都用过这个:

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 个答案:

答案 0 :(得分:7)

没有现有的扩展方法。让我解释为什么我认为这是(除了显而易见的“因为它没有指定,实施,测试,记录等”的原因)。

基本上,这种实现效率低下。从传递给In的参数构建数组(当使用params关键字时发生)是一个O(N)操作并导致无偿的GC压力(来自构造新的{{1}对象)。 T[]然后枚举该数组,这意味着您的原始代码在执行时间上增加了一倍以上(而不是通过短路评估进行一次部分枚举,您有一个完整的枚举后跟一个部分枚举)。

通过将Contains版本的扩展方法替换为X过载,从1到X类型{{1}的参数,可以减轻阵列构造引起的GC压力其中X是一些合理的数字......比如1-2打。但这并没有改变这样一个事实:你将X值传递到调用堆栈的新级别,只是为了检查可能少于X的值(即,它不会消除性能损失,只会减少它)。

然后又出现了另一个问题:如果您打算将此params扩展方法作为一系列链式T比较的替代品,那么您可能会忽略其他一些问题。使用In,您可以获得短路评估;对于传递给方法的参数,同样不适用。对于枚举,就像在你的例子中,这没关系。但请考虑以下代码:

||

以上(奇怪/不好 - 仅用于说明)代码不应该抛出||(它可能抛出if (0 == array.Length || 0 == array[0].Length || 0 == array[0][0].Length) { // One of the arrays is empty. } ,但这与我正在制造的点无关)。但是,使用IndexOutOfRangeException的“等效”代码可以:

NullReferenceException

我不是说你的In扩展想法很糟糕。在大多数情况下,如果使用得当,它可以节省打字,性能/内存成本也不会明显。我只是提出我为什么这种方法不适合作为内置库方法的想法:因为它的成本和限制可能会被误解,导致过度使用和次优代码。

答案 1 :(得分:1)

我认为你接近使用Contains电话。

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

这是Linq查询的常用方法。

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

顺便说一句:我喜欢你的扩展方法,我认为在某些情况下这可能非常有用。

答案 2 :(得分:1)

这就是它。您的In()扩展方法非常好。即使您使用的是以SQL建模的LINQ,您仍然必须使用Contains来指示在SQL中使用IN

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

转换为:

select * from table a where a.id in (.....)

答案 3 :(得分:1)

我什么都不知道。

对我来说,我认为可以像你一样编写这样的扩展方法,对于你经常需要的操作,你需要一个可读且方便的语法。这就是扩展方法的好处。

周围只有数百种有用的扩展方法。您可以要求其中许多,为什么它们不包含在.NET框架中?

并非所有内容都已包含在语言中。因此,请编写自己的库,并希望将来可以包含它。

答案 4 :(得分:0)

如果你想特别使用枚举,你可能会对FlagAttibute感兴趣。

答案 5 :(得分:0)

语言不能取悦所有人,但无论你是否这样做,或者编译器都做到了这一点并没有多大区别。该语言为您提供Any&amp; Contains

在你的世界中可能会很好,但是当别人必须拿起你的代码时,它会让他们感到困惑。

答案 6 :(得分:0)

通过使用表达式,您可以做得更好一点,这样可以在Linq2Sql等情况下正确使用该构造。

答案 7 :(得分:0)

如果您希望返回不同的值,可以使用.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);