Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
This document lists inconsistencies between Roslyn and the C# standard where they are known, organized by standard section.
Conversions
Implicit enum conversions from zero
From §10.2.4:
An implicit enumeration conversion permits a constant_expression (§11.21) with any integer type and the value zero to be converted to any enum_type and to any nullable_value_type whose underlying type is an enum_type.
Roslyn performs implicit enumeration conversions from constant expressions with types of float, double and decimal as well:
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;
}
}
Conversions are (correctly) not permitted from constant expressions which have a type of bool, other enumerations, or reference types.
Member lookup
From §12.5.1:
- Finally, having removed hidden members, the result of the lookup is determined:
- If the set consists of a single member that is not a method, then this member is the result of the lookup.
- Otherwise, if the set contains only methods, then this group of methods is the result of the lookup.
- Otherwise, the lookup is ambiguous, and a binding-time error occurs.
Roslyn instead implements a preference for methods over non-method symbols:
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 { }
Assumptions about well-known types/members
The compiler is free to make assumptions about the shape and behavior of well-known types/members.
It may not check for unexpected constraints, Obsolete attribute, or UnmanagedCallersOnly attribute.
It may perform some optimizations based on expectations that the types/members are well-behaved.
Note: the compiler should remain resilient to missing well-known types/members.
Interface partial methods
Interface partial methods are implicitly non-virtual, unlike non-partial interface methods and other interface partial member kinds, see a related breaking change and LDM 2025-04-07.
Roslyn breaking changes