【问题标题】:Weird switch behavior in .NET 4.NET 4 中的奇怪开关行为
【发布时间】:2010-06-02 12:54:44
【问题描述】:

我无法理解导致以下代码中的编译错误的原因:

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";
    }
}

我得到的错误在switch (test) 行:

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

Intellisence 告诉我 foo 操作将在运行时解决,这很好,因为我使用动态类型作为参数。但是我不明白 if 条件在 switch 没有时如何编译。

上面的代码只是我在应用程序 (VSTO) 中的简化版本,它是在将应用程序从 VSTO3 迁移到 VSTO4 后出现的,当时 VSTO 中的一种方法被更改为返回 dynamic 类型值而不是 object

谁能给我一个解释是什么问题。我知道如何解决它,但我想了解发生了什么。

【问题讨论】:

  • 看起来你不能直接输入开关
  • 因为switch 不是为所有可能的对象类型定义的
  • 每个人似乎都在回答,好像问题是“为什么我不能在dynamic 上使用switch?”我认为问题真的应该是“为什么test 首先输入为dynamic?”我知道 if foo 有返回不同类型的重载,test 必须是 dynamic;但由于它没有,我仍然无法在这里找出“真正”问题的答案。
  • 我怀疑它在 C# 规范中 - 如果一个表达式有一个 dynamic 输入,那么输出也是 dynamic,不管表达式是否只有一种可能的解释(因为,比如说,您可以使用反射添加另一种方法)

标签: .net .net-4.0 switch-statement


【解决方案1】:

因为您正在动态调用方法,所以结果也是 dynamic(因为返回值可能是 anything - 它直到运行时才知道)。而且您不能在 dynamic 变量类型上使用 switch

【讨论】:

  • dynamicif 可以吗?
  • @RaYell:你不会在dynamic 上“if” - 你在dynamic 上比较平等==。这很好定义。
  • 为什么返回值可以是任何值? foo 返回 string。我必须阅读这个dynamic 的疯狂......
  • @Dan,因为 foo 可能有多个重载,并且因为 x 是动态的,所以在知道 x 的类型之前,您无法准确决定调用哪个,而直到运行时才会发生。跨度>
  • @Dan Tao:Bill Wagner 在 Effective C# (IMO) 中给出了很好的解释
【解决方案2】:

switch 表达式的类型由编译器在编译时计算。 dynamic 的类型是在运行时评估的,因此编译器无法验证它是否是(或可转换为)允许的类型之一(根据 C# 4 Language Specification 是 sbyte、byte、short、ushort、int、 uint、long、ulong、bool、char、string 或枚举类型)。

【讨论】:

    【解决方案3】:

    正如马特·艾伦所说,但有更多背景知识。

    对于switch 语句:来自 C# 语言规范 v4.0:

    switch 语句的管理类型由 switch 表达式建立。

    • 如果switch表达式的类型是sbyte,byte,short,ushort,int,uint,long,ulong,bool987654331@,@3 、stringenum-type,或者如果它是对应于这些类型之一的可空类型,那么它就是 switch 语句的管理类型。
    • 否则,从 switch 表达式的类型到以下可能的控制类型之一必须存在一个用户定义的隐式转换 (§6.4):sbytebyteshortushortintuintlongulongcharstring,或者,对应于其中一种类型的可空类型。
    • 否则,如果不存在此类隐式转换,或者存在多个此类隐式转换,则会发生编译时错误。

    对于if 语句,表达式被评估为布尔运算。由于在变量赋值的方法调用中使用了dynamic,表达式评估被推迟到运行时。从上面的规范看来,switch 需要在编译时评估开关类型。

    【讨论】:

      【解决方案4】:

      这是一些意想不到的行为 - 我本来希望将 var 设置为显式返回字符串以正确推断字符串类型的方法。哦,好吧.....

      如果你替换:

      var test = foo(x);

      与:

      字符串测试 = foo(x);

      如你所知,一切都会编译。

      这是安全的,因为您已将 foo() 声明为返回一个字符串,而且从长远来看可能更直观地阅读。

      【讨论】:

      • 'var' 无法在运行时解析,因为 x 是动态的。可能有多个具有不同参数和返回类型的 'foo' 重载。直到知道 x 的类型,才能解决到底发生了什么,直到运行时才会发生。实际发生的是 var 被解析为“动态”,这就是为什么它不能在开关中使用。如果将鼠标指针悬停在“var”上,您将看到 Visual Studio 将其解析为“动态”
      • 是的 - 我看到了。我想我只是假设当在进行方法调用的范围内存在单个方法时,var 推断会更聪明。但你知道他们对假设的看法...... =)
      【解决方案5】:

      Switch 语句仅支持数字、字符、枚举和字符串。 dynamic 不是这些东西。如果你假设 x 是一个字符串,你可以直接转换它:

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

      如果不是,您只会收到运行时错误。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-16
        • 2013-11-06
        • 2016-05-15
        • 1970-01-01
        • 1970-01-01
        • 2014-10-31
        相关资源
        最近更新 更多