【问题标题】:Using implicit conversion operators in combination with switch将隐式转换运算符与 switch 结合使用
【发布时间】:2015-01-14 21:16:15
【问题描述】:

不清楚的行为,如果我声明类型:

struct Token
{
    public static implicit operator int(Token x)
    {
        return 0;
    }

    public static implicit operator string(Token x)
    {
        return "";
    }
}

我们有两个隐式转换。 工作文件,如果我使用

var t = new Token();

if (t == "123")
{

}

CS0151:switch 表达式或 case 标签必须是 bool、char、string、integral、enum 或相应的可为 null 类型

如果我使用:

switch (t)
{
    case "123" :
    {
        break;
    }
}

但如果我删除 int 隐式转换,那么错误就会消失。

struct Token
{
    public static implicit operator string(Token x)
    {
        return "";
    }
}

是编译器的错误还是正确的行为?

【问题讨论】:

    标签: c#


    【解决方案1】:

    这是正确的行为。来自规范,8.7.2 The switch statement

    从 switch 表达式的类型到以下可能的控制类型之一必须存在一个用户定义的隐式转换 (Section 6.4):sbyte、byte、short、ushort、int、uint、long、ulong、char , 细绳。如果不存在此类隐式转换,或者存在多个此类隐式转换,则会发生编译时错误。


    我们还可以在Conversions.UserDefinedImplicitConversions 看到实现规范的(下一版本)编译器源代码。
    请注意,我已经删除了一些代码和 cmets,这只是为了大致了解一下:

    UserDefinedConversionResult? exactConversionResult = null;
    
    foreach (UserDefinedConversionAnalysis analysis in u)
    {
        TypeSymbol tx = analysis.ToType;
        if (tx.IsValidSwitchGoverningType(isTargetTypeOfUserDefinedOp: true))
        {
            if (!exactConversionResult.HasValue)
            {
                exactConversionResult = UserDefinedConversionResult.Valid(u, best.Value);
                continue;
            }
    
            return UserDefinedConversionResult.Ambiguous(u);
        }
    }
    
    // If there exists such unique TX in suitableTypes, then that operator is the  
    // resultant user defined conversion and TX is the resultant switch governing type.
    // Otherwise we either have ambiguity or no applicable operators.
    return exactConversionResult.HasValue ?
        exactConversionResult.Value :
        UserDefinedConversionResult.NoApplicableOperators(u);
    

    基本上,代码会遍历隐式转换并将找到的第一个转换保留为可以出现在switch 中的类型。如果找到另一种类型,则返回Ambiguous。如果它恰好找到一种类型,则返回它。
    同样,这是代码的简短版本,完整的代码处理更多的案例和粗略的兼容性。

    【讨论】:

    • 我已经添加了来自 Roslyn 的相关代码。这不是强制性的,因为规范是王道,但我想看看我是否能找到它。天真地,我期待 Types.Count == 1 在某个地方。 :P
    【解决方案2】:

    编译器的困惑似乎是可以理解的。 switch 语句可以在 intstring 上运行。您将其传递给 Token ,其中包含对两者的隐式转换。编译器应该选择哪一个?它无法知道哪个是首选。隐式构造函数没有优先级。

    if 的情况下,很明显您正在与字符串进行比较,因此使用了转换。但是切换是模棱两可的。该错误并不完全清楚,但我假设,不知道选择哪个转换,它都不选择,尝试将Token 实例本身放入开关,从而显示此错误。

    【讨论】:

      【解决方案3】:

      这是正确的行为,因为 switch 语句不知道将 t 转换为什么类型:

      switch (t)
      {
          case "123" :
              break;
          case 0:
              break;
      }
      

      这应该说清楚,因为t 不能转换为intstring,但以下工作:

      switch ((string)t)
      {
          case "123" :
              break;
      }
      

      现在你清楚地定义了你想要切换一个字符串...

      【讨论】:

        猜你喜欢
        • 2014-02-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-12
        • 1970-01-01
        • 2017-03-23
        • 2010-10-27
        • 2019-01-08
        相关资源
        最近更新 更多