我觉得很难找到一个相当简单的方法。
我想我们都用过这个:
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()方法。
答案 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);