C# switch statement limitations - why?

2019-01-01 03:54发布

When writing a switch statement, there appears to be two limitations on what you can switch on in case statements.

For example (and yes, I know, if you're doing this sort of thing it probably means your object-oriented (OO) architecture is iffy - this is just a contrived example!),

  Type t = typeof(int);

  switch (t) {

    case typeof(int):
      Console.WriteLine("int!");
      break;

    case typeof(string):
      Console.WriteLine("string!");
      break;

    default:
      Console.WriteLine("unknown!");
      break;
  }

Here the switch() statement fails with 'A value of an integral type expected' and the case statements fail with 'A constant value is expected'.

Why are these restrictions in place, and what is the underlying justification? I don't see any reason why the switch statement has to succumb to static analysis only, and why the value being switched on has to be integral (that is, primitive). What is the justification?

16条回答
回忆,回不去的记忆
2楼-- · 2019-01-01 04:18

Judah's answer above gave me an idea. You can "fake" the OP's switch behavior above using a Dictionary<Type, Func<T>:

Dictionary<Type, Func<object, string,  string>> typeTable = new Dictionary<Type, Func<object, string, string>>();
typeTable.Add(typeof(int), (o, s) =>
                    {
                        return string.Format("{0}: {1}", s, o.ToString());
                    });

This allows you to associate behavior with a type in the same style as the switch statement. I believe it has the added benefit of being keyed instead of a switch-style jump table when compiled to IL.

查看更多
栀子花@的思念
3楼-- · 2019-01-01 04:18

I agree with this comment that using a table driven approach is often better.

In C# 1.0 this was not possible because it didn't have generics and anonymous delegates. New versions of C# have the scaffolding to make this work. Having a notation for object literals is also helps.

查看更多
与风俱净
4楼-- · 2019-01-01 04:22

I don't see any reason why the switch statement has to succomb to static analysis only

True, it doesn't have to, and many languages do in fact use dynamic switch statements. This means however that reordering the "case" clauses can change the behaviour of the code.

There's some interesting info behind the design decisions that went into "switch" in here: Why is the C# switch statement designed to not allow fall-through, but still require a break?

Allowing dynamic case expressions can lead to monstrosities such as this PHP code:

switch (true) {
    case a == 5:
        ...
        break;
    case b == 10:
        ...
        break;
}

which frankly should just use the if-else statement.

查看更多
余生请多指教
5楼-- · 2019-01-01 04:22

According to the switch statement documentation if there is an unambiguous way to implicitly convert the the object to an integral type, then it will be allowed. I think you are expecting a behavior where for each case statement it would be replaced with if (t == typeof(int)), but that would open a whole can of worms when you get to overload that operator. The behavior would change when implementation details for the switch statement changed if you wrote your == override incorrectly. By reducing the comparisons to integral types and string and those things that can be reduced to integral types (and are intended to) they avoid potential issues.

查看更多
登录 后发表回答