代码之家  ›  专栏  ›  技术社区  ›  Daniel

C#编译器在应该出错时失败

  •  1
  • Daniel  · 技术社区  · 7 月前

    编译器无法检测到第3行将出错:

    IList<IList<double>> xs = new List<IList<double>> { new List<double> { 2 } };
    IList<string> x0 = xs.First();      // does not compile, as expected
    foreach (IList<string> x in xs) { } // works, unexpectedly!
    

    (即使没有错误,Visual Studio在第3行确实建议存在隐式转换,这可能会在运行时失败。)

    有趣的是,编译器在这里成功地检测到了这个问题:

    IList<double> xs = new List<double> { 2 };
    string x0 = xs.First();      // does not compile, as expected
    foreach (string x in xs) { } // also does not compile, as expected
    

    第3行只给出建议而不是错误,就像第2、5和6行一样,有充分的理由吗?

    1 回复  |  直到 7 月前
        1
  •  1
  •   Ivan Petrov    7 月前
    foreach (IList<string> x in xs)
    

    未编译为

    while (enumerator.MoveNext()) {
        // (like your second line)
        IList<string> x = enumerator.Current; // Current being IList<double>
    }
    

    但是为了

    while (enumerator.MoveNext()) {
        IList<string> x = (IList<string>)enumerator.Current;
    }
    

    这是因为 compiler 将尽力帮助我们 显式转换 我们还没有明确定义(说实话,由于语法简洁,我们无法定义):

    如果T(迭代)没有显式转换(§10.3) type)转换为V(foreach语句中的local_variable_type) 则产生错误并且不采取进一步的步骤。

    因此,如果有,它将被放在那里:

    IList<string> x = (IList<string>)enumerator.Current;
    

    根据the 10.3.5 Explicit reference conversions 语言规范中的部分允许进行这样的转换(在我们的例子中是从 IList<double> IList<string> ):

    从任何interface_type S到任何interface_type T,前提是S不是 来源于T。

    对于第二组示例,没有可能的显式转换 double string -这就是为什么编译器在 foreach 部分也是。