偏离 C# 标准规范

本文档列出了已知的 Roslyn 和 C# 标准之间的不一致之处,并按照标准的章节进行组织。

转换

从零值开始的隐式枚举转换

§10.2.4

隐式枚举转换允许将任何整数类型并且值为零的常量表达式§11.21)转换为任何enum_type,以及转换为底层类型为enum_type的任何nullable_value_type

Roslyn 还对具有类型 floatdoubledecimal 的常量表达式进行隐式枚举转换:

enum SampleEnum
{
    Zero = 0,
    One = 1
}

class EnumConversionTest
{
    const float ConstFloat = 0f;
    const double ConstDouble = 0d;
    const decimal ConstDecimal = 0m;

    static void PermittedConversions()
    {
        SampleEnum floatToEnum = ConstFloat;
        SampleEnum doubleToEnum = ConstDouble;
        SampleEnum decimalToEnum = ConstDecimal;
    }
}

不允许(正确)从具有类型 bool、其他枚举或引用类型的常量表达式进行转换。

成员查找

§12.5.1

  • 最后,移除隐藏成员后,查找结果被确定。
    • 如果集由不是方法的单个成员组成,则此成员是查找的结果。
    • 否则,如果集仅包含方法,则此组方法是查找的结果。
    • 否则,查找会变得模棱两可,并且会发生绑定时间错误。

Roslyn 实现了一种对方法而非非方法符号的偏好:

var x = I.M; // binds to I1.M (method)
x();

System.Action y = I.M; // binds to I1.M (method)

interface I1 { static void M() { } }
interface I2 { static int M => 0;   }
interface I3 { static int M = 0;   }
interface I : I1, I2, I3 { }
I i = null;
var x = i.M; // binds to I1.M (method)
x();

System.Action y = i.M; // binds to I1.M (method)

interface I1 { void M() { } }
interface I2 { int M => 0;   }
interface I : I1, I2 { }

有关已知类型/成员的假设

编译器可以自由地假设已知类型/成员的形状和行为。 它可能不会检查意外的约束、 Obsolete 属性或 UnmanagedCallersOnly 属性。 它可能会根据类型/成员的行为良好的预期执行一些优化。 注意:编译器应具有在缺少已知类型/成员时的恢复能力。

接口局部方法

接口分部方法是隐式非虚拟方法,与非分部接口方法和其他接口分部成员类型不同,请参阅 相关的中断性变更LDM 2025-04-07