Abweichungen vom C#-Standard

In diesem Dokument werden Inkonsistenzen zwischen Roslyn und dem C#-Standard aufgelistet, in dem sie bekannt sind, geordnet nach Standardabschnitt.

Konvertierungen

Implizite Enum-Konvertierungen von 0

Ab §10.2.4:

Eine implizite Enumerationskonvertierung ermöglicht eine constant_expression (§12.25) mit einem beliebigen ganzzahligen Typ und dem Wert Null, der in eine beliebige enum_type und in alle nullable_value_type konvertiert werden kann, deren zugrunde liegender Typ ein enum_type ist.

Roslyn führt auch implizite Enumerationskonvertierungen aus konstanten Ausdrücken mit den Typen float, double und decimal aus.

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

Konvertierungen sind ( ordnungsgemäß) nicht von Konstantenausdrücken zulässig, die einen Typ von bool, andere Enumerationen oder Referenztypen aufweisen.

Mitgliedersuche

Ab §12.5.1:

  • Nachdem ausgeblendete Member entfernt wurden, wird schließelich das Ergebnis der Suche bestimmt:
    • Besteht das Set aus einem einzigen Mitglied, das keine Methode ist, so ist dieses Mitglied das Ergebnis der Mitgliedersuche.
    • Ansonsten, wenn die Menge nur Methoden enthält, dann ist diese Methodengruppe das Ergebnis der Abfrage.
    • Andernfalls ist die Suche mehrdeutig, und ein Bindungszeitfehler tritt auf.

Roslyn implementiert stattdessen eine Präferenz für Methoden gegenüber Symbolen, die keine Methoden sind.

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 { }

Annahmen zu bekannten Typen/Mitgliedern

Der Compiler ist frei, Annahmen über die Form und das Verhalten bekannter Typen/Member zu treffen. Es wird möglicherweise nicht auf unerwartete Einschränkungen, das Obsolete Attribut oder das UnmanagedCallersOnly Attribut überprüft. Es kann einige Optimierungen basierend auf der Erwartung durchführen, dass sich die Typen/Mitglieder erwartungsgemäß verhalten. Hinweis: Der Compiler sollte stabil bleiben, wenn bekannte Typen/Member fehlen.

Partielle Schnittstellenmethoden

Partielle Schnittstellenmethoden sind implizit nicht virtuell, im Gegensatz zu nicht partiellen Schnittstellenmethoden und anderen Arten von partiellen Schnittstellenelementen, siehe eine relevante Änderung, die einen Bruch darstellt und LDM 2025-04-07.