代码之家  ›  专栏  ›  技术社区  ›  Robert H.

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

  •  19
  • Robert H.  · 技术社区  · 14 年前

    我很难找到一个简单的方法。

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

    然而,为我在框架中找不到的东西编写自己的方法感觉很肮脏。

    8 回复  |  直到 14 年前
        1
  •  7
  •   Dan Tao    14 年前

    没有像您现有的那样的扩展方法。让我解释一下为什么我认为这是(除了明显的“因为它没有被指定、实现、测试、记录等等”的原因)。

    In (当您使用 params 关键字)是一个O(N)操作,并导致无偿的GC压力(来自新的 T[] 对象)。 Contains 然后对该数组进行枚举,这意味着原始代码的执行时间增加了一倍以上(不是通过短路求值进行部分枚举,而是先进行一次完整枚举,然后进行部分枚举)。

    阵列结构引起的GC压力 通过替换 参数 T 其中X是一个合理的数字。。。大概12打。但这并没有改变这样一个事实,即您将X值传递到调用堆栈的新级别上,只是为了检查可能少于X的值(即,它不会消除性能损失,只会降低性能损失)。

    || 相比之下,你可能忽略了其他一些东西。与 ,得到短路评估;对于传递给方法的参数,情况并非如此。在枚举的情况下,就像在您的示例中一样,这并不重要。但请考虑以下代码:

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

    上面的代码(奇怪/糟糕——仅用于说明)不应该抛出 IndexOutOfRangeException NullReferenceException ,但这与我的观点无关)。但是,“等效”代码使用 我们可以:

    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.
    }
    

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

        2
  •  1
  •   Jerod Houghtelling    14 年前

    我认为你已经接近使用 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
  •  1
  •   James Curran    14 年前

    In() 扩展方法很不错。即使您使用的是以SQL为模型的LINQ,您仍然必须使用 Contains 表示使用 IN 在SQL中。

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

    select * from table a where a.id in (.....)
    
        4
  •  1
  •   Stefan Steinegger    14 年前

    我什么都不知道。

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

    只有数百种有用的扩展方法。你可以问他们中的许多人,为什么他们不包括在.NET框架中?

        5
  •  0
  •   Douglas    14 年前

    你可能会对 FlagAttibute

        6
  •  0
  •   Nix    14 年前

    语言不能让每个人都满意,但不管你是这样做的,还是编译器这样做的,都没有多大区别。语言给你 Any & Contains

    在你的世界里,这也许是件好事,但当别人不得不拿起你的代码时,他们会感到困惑。

        7
  •  0
  •   leppie    14 年前

    您可以做得更好一些,通过使用表达式,这将允许在Linq2Sql这样的情况下正确地使用构造。

        8
  •  0
  •   James Hull    14 年前

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