C# In() 方法? (如 SQL)

发布于 2024-09-13 03:57:07 字数 913 浏览 4 评论 0原文

我很难找到我认为应该是相当简单的方法。

我想我们都用过这个:

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() 方法。

I'm having a hard time finding what, I think, should be a fairly simple method.

I think we've all used this:

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

In C#, I've have to write stuff like this:

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

This works, but it's just wordy.

Out of frustration, I wrote an extension method to accomplish what I'm trying to do.

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

Now, I can write shorter code:

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

It feels dirty, however, to write my own method for something that I just can't find in the framework.

Any help you folks can offer would be great,
Thanks

EDIT: Thanks everyone for the in-depth anaylsis. I think I'll keep using my In() method.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

此生挚爱伱 2024-09-20 03:57:07

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

基本上,这种实现必然是低效的。从传递给 In 的参数构造一个数组(如使用 params 关键字时发生的情况)是一个 O(N) 操作,会导致无谓的 GC 压力(来自构造一个新的 T[] 对象)。 Contains 然后枚举该数组,这意味着您的原始代码的执行时间增加了一倍多(而不是通过短路求值进行部分枚举,您将获得一个完整枚举,然后是部分枚举)枚举)。

通过使用采用 T 类型的 1 到 X 个参数的 X 重载替换扩展方法的 params 版本,可以在一定程度上减轻由数组构造引起的 GC 压力 其中 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 扩展想法是一个坏想法。在大多数情况下,如果使用得当,它可以节省打字时间,并且性能/内存成本不会引人注目。我只是提供我的想法,为什么这种方法不适合作为内置库方法:因为它的成本和限制可能会被误解,导致过度使用和次优代码。

There's no existing extension method like what you have. Let me explain why I think that is (aside from the obvious "because it wasn't specified, implemented, tested, documented, etc." reason).

Basically, this implementation is necessarily inefficient. Constructing an array from the parameters passed to In (as happens when you use the params keyword) is an O(N) operation and causes gratuitous GC pressure (from the construction of a new T[] object). Contains then enumerates over that array, which means your original code has been more than doubled in execution time (instead of one partial enumeration via short-circuited evaluation, you've got one full enumeration followed by a partial enumeration).

The GC pressure caused by the array construction could be alleviated somewhat by replacing the params version of the extension method with X overloads taking from 1 to X parameters of type T where X is some reasonable number... like 1-2 dozen. But this does not change the fact that you're passing X values onto a new level of the call stack only to check potentially less than X of them (i.e., it does not eliminate the performance penalty, only reduces it).

And then there's another issue: if you intend for this In extension method to serve as a replacement for a bunch of chained || comparisons, there's something else you might be overlooking. With ||, you get short-circuited evaluation; the same doesn't hold for parameters passed to methods. In the case of an enum, like in your example, this doesn't matter. But consider this code:

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

The above (weird/bad -- for illustration only) code should not throw an IndexOutOfRangeException (it could throw a NullReferenceException, but that's irrelevant to the point I'm making). However, the "equivalent" code using In very well could:

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

I'm not saying your In extension idea is a bad one. In most cases, where used properly, it can save on typing and the performance/memory cost will not be noticeable. I'm just offering my thoughts on why a method of this sort would not be appropriate as a built-in library method: because its costs and limitations would likely be misunderstood, leading to over-use and suboptimal code.

送君千里 2024-09-20 03:57:07

我认为您已经接近使用 Contains 调用。

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

这是 Linq 查询的常见方法。

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

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

I think you are close with using the Contains call.

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

This is the common approach for Linq queries.

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

BTW: I like your extension method, I think that could be extremely useful in certain situations.

紙鸢 2024-09-20 03:57:07

差不多就这样了。您的 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 (.....)

That's pretty much it. Your In() extension method is pretty nice. Even if you are using LINQ, which is modeled after SQL, you still have to use Contains to indicate using IN in the SQL.

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

Translates to:

select * from table a where a.id in (.....)
叹沉浮 2024-09-20 03:57:07

我不知道别的事。

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

周围只有数百种有用的扩展方法。您可能会问其中很多,为什么它们没有包含在 .NET 框架中?

并非所有内容都可以包含在语言中。所以自己写一个库,希望以后能被收录。

I don't know anything else.

For me, I think it is just ok to write such extension methods as you did, for operations you often need and you want a readable and handy syntax. That's what extension methods are good for.

There are just hundreds of useful extension methods around. You could ask for many of them, why aren't they included in the .NET framework?

Not everything can be already included in a language. So write your own library and hope that it will be included in the future.

乄_柒ぐ汐 2024-09-20 03:57:07

如果您愿意,您可能会对 FlagAttibute 感兴趣尤其是使用枚举来做到这一点。

You might be interested in the FlagAttibute if you're wanting to do this particularly with Enums.

心舞飞扬 2024-09-20 03:57:07

语言不可能让所有人都满意,但无论是你做的,还是编译器做的,都没有太大区别。该语言为您提供 Any包含

在您的世界中可能很好,但当其他人有拿起你的代码会让他们感到困惑。

Languages can't please everyone, but whether you do it, or the compiler does it there isn't much difference. The language gives you Any & Contains

In might be nice in your world, but when someone else has to pick up your code it will be confusing to them.

旧城烟雨 2024-09-20 03:57:07

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

You could do something a little better, by using Expressions, this will allow the construct to be properly utilized in cases like Linq2Sql.

々眼睛长脚气 2024-09-20 03:57:07

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

You could use the .Intersect extension method if you would like distinct values returned. Eg.

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

var results = test.Intersect<string>(test2);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文