RaYell
RaYell

Reputation: 70414

Weird switch behavior in .NET 4

I have a problem understanding what's causes the compilation error in the code below:

static class Program
{
    static void Main()
    {
        dynamic x = "";
        var test = foo(x);

        if (test == "test")
        {
            Console.WriteLine(test);
        }

        switch (test)
        {
            case "test":
                Console.WriteLine(test);
                break;
        }
    }

    private static string foo(object item)
    {
        return "bar";
    }
}

The error I get is in switch (test) line:

A switch expression or case label must be a bool, char, string, integral, 
enum, or corresponding nullable type.

Intellisence shows me that foo operation will be resolved on runtime, which is fine because I'm using a dynamic type as a param. However I don't understand how if condition compiles fine when switch doesn't.

Code above is just simplified version of what I have in my application (VSTO) which appeared after migrating the app from VSTO3 to VSTO4 when one method in VSTO was changed to return dynamic type values instead of object.

Can anyone give me an explanation what's the problem. I know how to resolve it but I'd like to understand what's happening.

Upvotes: 10

Views: 2040

Answers (5)

Richard Szalay
Richard Szalay

Reputation: 84754

Switch statements only support numbers, chars, enums and strings. dynamic is none of those things. If you assume that x is a string, you can just cast it:

dynamic x = ""; 
string test = (string)foo(x); 

You'll just get a runtime error if it's not.

Upvotes: 0

dariom
dariom

Reputation: 4578

As Matt Ellen says, but with a little more background.

For the switch statement: from the C# Language Specification v4.0:

The governing type of a switch statement is established by the switch expression.

  • If the type of the switch expression is sbyte, byte, short, ushort, int, uint, long, ulong, bool, char, string, or an enum-type, or if it is the nullable type corresponding to one of these types, then that is the governing type of the switch statement.
  • Otherwise, exactly one user-defined implicit conversion (§6.4) must exist from the type of the switch expression to one of the following possible governing types: sbyte, byte, short, ushort, int, uint, long, ulong, char, string, or, a nullable type corresponding to one of those types.
  • Otherwise, if no such implicit conversion exists, or if more than one such implicit conversion exists, a compile-time error occurs.

For the if statement the expression is evaluated as a Boolean operation. The expression evaluation is deferred to run-time because of the use of dynamic in the method call in the variable assignment. From the specification above, it looks like switch requires compile-time evaluation of switch types.

Upvotes: 2

Fredrik Mörk
Fredrik Mörk

Reputation: 158309

The type of the switch expression is evaluated by the compiler, at compile time. The type of dynamic is evaluated in runtime, so the compiler cannot verify whether it is (or is convertible to) one of the allowed types (which, according to the C# 4 Language Specification is sbyte, byte, short, ushort, int, uint, long, ulong, bool, char, string, or an enum-type).

Upvotes: 3

Andrew Anderson
Andrew Anderson

Reputation: 3449

That is some unexpected behavior - I would have expected a var set to a method that explicitly returns a string to properly infer a string type. Oh well.....

If you replace:

var test = foo(x);

with:

string test = foo(x);

it all compiles as you know.

This is safe since you've declared foo() as returning a string, and perhaps a little more intuitive to read in the long run anyways.

Upvotes: 0

thecoop
thecoop

Reputation: 46108

Because you're calling a method dynamically, the result is also a dynamic (as the return value could be anything - it doesn't know until runtime). And you can't switch on a dynamic variable type.

Upvotes: 10

Related Questions