开发者

C#. Do if( a == (b or c or d)). Is it possible?

Is there another way to write something like this:

if (a == x || a == y || a == z)

One way that I开发者_如何学编程 found is doing it like this:

if( new [] {x,y,z}.Contains(a))

Are there other good ways?


I often use an extension method that mimics SQLs IN:

public static bool IsIn<T>(this T obj, params T[] collection) {
   return collection.Contains(obj);
}

That way I can do

if(a.IsIn(b, c, d)) { ... }


You have the classic switch statement :

switch(a) {
    case x:
    case y:
    case z:
        // Do stuff
        break;
}


Just for fun:

using System;

static class Program {

    static bool In(this object obj, params object[] values) {
        foreach (object value in values) {
            if (obj.Equals(value)) {
                return true;
            }
        }
        return false;
    }

    static void Main(string[] args) {
        bool test1 = 3.In(1, 2, 3);
        bool test2 = 5.In(1, 2, 3);
    }
}

But I really think that the best way is to write the plain check

if(a == x || a == y || a == z)

As everybody will understand immediately what it does.


Your solution to rewrite it as

if( new [] {x,y,z}.Contains(a))

is not a good move.

You've take a simple efficient logical operation, which every programmer easily understands and which contains short-circuiting logic to speed it up and instead you've produced code that requires a moment to understand and which is considerably less efficient.

Sometimes your fellow engineers will prefer it if you don't try to be "clever"!


Consider a case where a == x, and y and z are slow-to-evaluate, expensive functions.

  • In if(a == x || a == y || a == z) you have the benefit of the short-circuit ||-operator, so you y and z won't be evaluated.
  • If you make an array with new[] { x, y, z } - y and z will be evaluated every time.

The 'trick' with .Contains() would be more useful if there was an elegant syntax to create lazy-evaluated sequence (IEnumerable<T>). i.e. something like yield return x; yield return y;..., but inlined and shorter.


Fun fact, as of C#9 this is possible

var c ='b';

if (c is 'a' or 'b' or 'c')
  Console.WriteLine("yes");

Which compiles to

if (c == 'a' || c == 'b' || c == 'c')
{
   Console.WriteLine("yes");
}

Or you can get more creative

if (c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z') or '.' or ',')
   Console.WriteLine("yes");

Which would roughly compile to (according to sharp io)

if (c >= 'a')
{
   if (c <= 'z')
   {
      goto IL_0025;
   }
}
else if (c >= 'A')
{
   if (c <= 'Z')
   {
      goto IL_0025;
   }
}
else if (c == ',' || c == '.')
{
   goto IL_0025;
}
bool flag = false;
goto IL_002b;
IL_0025:
flag = true;
goto IL_002b;
IL_002b:
if (flag)
{
   Console.WriteLine("yes");
}

Or use it in a switch

switch (c)
{
   case 'a' or 'b' or 'c':
      Console.WriteLine("yes");
   break;
}


So, you want to replace a simple, efficent language construct that contains short-circuit optimisations into something much slower that has the potential for throwing exceptions?

However, if the items you want to compare against are not fixed in quantity, i.e. at run time it could be t,u,v,w,x,y,z,etc..., then the Collection.Contains method is the only option, but then you'd be passing collection objects around rather than individual values and so there's little memory allocation ovrehead.

If you've got a large number of items to compare 'a' against, but the items are not dynamic at run time then a switch statement might be a better fit.


Why would you need yet another way? Since it isn't a matter of functionality, I would guess the point is to improve readability. If you have a few variables with meaningful names, it would be more readable to just compare by using ==. If you have more, you can use Contains against a list as in your other sample. Yet another way would be comparing against enum flags:

[Flags]
public enum Size
{
    Small = 1,
    Medium = 2,
    Large = 4
}

And then to find out if mySize is in Small or Medium:

selectedSizes = Size.Small | Size.Medium;
mySize = Size.Small;
if (mySize & selectedSizes)
{
  ... 
}


if(a==x?true:a==y?true:a==z?true:false)


Try this

var res2 = new[] { 1, 2, 3 }.Any(x => x == 2);


For instance, your logic is like that:

if(a==x || a== y|| a==z)
{
    DoSomething();
} 
else
{
   DoOtherThings();
}

will equivalent to:

if(a!=x&& a != y && a!= z)
{
   DoOtherThings();
}
else
{
   DoSomething();
}

Cheers.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜