tags:

views:

319

answers:

8

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.

A: 

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

Douglas
That attribute only has cosmetic semantics.
leppie
@leppie The framework uses this attribute in the ToString implementation of the enumeration when the enumerant matches no value, and it is useful as documentation.
Trillian
-1 It won't help at all. The Flags attribute deals with an entirely orthogonal issue, namely, composition of multiple enum values in a single variable. The OP has only one value in the variable.
siride
A: 

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.

Nix
+1  A: 

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.

Jerod Houghtelling
he is using Contains in his extension method.
Stefan Steinegger
+1  A: 

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 (.....)
James Curran
+1  A: 

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.

Stefan Steinegger
A: 

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

leppie
A: 

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);
James Hull
+7  A: 

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.

Dan Tao
How do you know is O(N)?
mathk
@mathk - Well, if you have n items, you have to add each of those n items to the array. There's no way you can ignore items; if you do, you haven't created an array of all n items by definition. So it has to be at least O(n).
jloubert
Since it is an immutable array you can leave it on he stack no need to move items. Donno how C# have make it out but it could be O(1)
mathk
@mathk: You can only "leave it on the stack" if it exists in the first place. If your code is several equality comparisons connected by the short-circuited `||` operator, there's no array. If it's a method call with a `params` parameter passed to it, there's an array. That array has to be constructed somewhere; it cannot magically spring into existence on the stack.
Dan Tao
Yeap of course but you wont have more than 100 arguments so it is still O(1)
mathk
@mathk: Sorry, you've lost me. How exactly are you getting from "won't have more than 100 arguments" to O(1)? I don't see any connection between these statements.
Dan Tao
Well simple, let f(x) being the number of push, since 1 <= f(x) <= 100 then f(x) = O(1). QED
mathk
@mathk: OK, are you joking? Now you are just baffling me!
Dan Tao
Well I admit is not quite right but just to say that you can't really say that In() will make things slower. We all know that we are bad at discovering bottleneck beforehand. I think, just write your software the more readable as you can, then try to found out were is your bottleneck if you ever have performance issue.
mathk
Could you add to your answer what you mean by "gratuitous GC pressure"? I have heard of "memory pressure", is that the same thing? Is using the params keyword well known to create inefficiencies?
Ash