X is enum - is this according to spec?
-
17-05-2021 - |
Pergunta
Test if an object is an Enum discusses testing an object with is Enum
to see if it contains an enum value.
Is this specified anywhere in the spec? The entry on is
(7.10.10 in Version 4.0) lists the following possible right-hand values:
- anonymous function
- method group
- null
- reference type ** This might be an enum?
- nullable type
- non-nullable value type ** This might be an enum?
Assuming that an enum value matches "reference type" from the list above - the spec states as follows:
...the result is true if D [the dynamic type of the RHS)] and T [the LHS] are the same type, if D is a reference type and an implicit reference conversion from D to T exists, or if D is a value type and a boxing conversion from D to T exists.
Are any of these conditions strictly true in the case of is Enum
? There is no compiler support for, say, is class
or is struct
.
So is the support for is Enum
according to the specification, or is it an implementation decision?
Solução
There is no support for is class
or is struct
, because there is no common base type that would differentiate classes or structs from other types. is Enum
works, because System.Enum
is an actual type that is the base of all enums. And Enum
is a reference type, so the last part applies:
if D is a value type and a boxing conversion from D to T exists
D
(the type of the expression on the left side) is a value type. And T
is Enum
, which is a base type of D
. So there is a boxing conversion from D
to Enum
and so the value of the expression is true
.
The boxing conversion from any enum to Enum
is specified explicitly in §14.4 The System.Enum type:
The type
System.Enum
is the abstract base class of all enum types (this is distinct and different from the underlying type of the enum type), and the members inherited fromSystem.Enum
are available in any enum type. A boxing conversion exists from any enum type toSystem.Enum
, and an unboxing conversion exists fromSystem.Enum
to any enum type.Note that
System.Enum
is not itself an enum-type. Rather, it is a class-type from which all enum-types are derived. The typeSystem.Enum
inherits from the typeSystem.ValueType
, which, in turn, inherits from typeobject
. At run-time, a value of typeSystem.Enum
can be null or a reference to a boxed value of any enum type.
Outras dicas
Enum
is a reference type.
typeof(Enum).IsValueType => false
Interestingly,
typeof(ValueType).IsValueType => false
Enum is an actual type where as class and struct are not. Therefore, Enum can be used on the right-hand side where as class and struct cannot.
What is being asked here has not been entirely clear to me but I hope I got it now.
Given the code below:
void F(Object obj) {
var isEnum obj is Enum;
...
}
What parts of the C# standard specifies that isEnum
is true when obj
is an instance of an enum type?
In 14.9.10 is operator in the C# Language Specification there are five bullets describing how it is evaluated:
The 1st bullet is about cases where
obj
has a more specific type thanSystem.Object
.The 2nd bullet is about nullable types.
The 4th bullet is about generic types.
The 5th bullet is when there are no matches and the
is
operator evaluates to false which we know it doesn't.
You would expect that the 3rd bullet applies to the code above. The 3rd bullet has four sub-bullets:
The 1st sub-bullet applies when
obj
is null.The 2nd sub-bullet is about nullable types.
The 4th sub-bullet is when there are no matches and the
is
operator evaluates to false which we know it doesn't.
You would expect the the 3rd sub-bullet applies:
Otherwise, let R be the run-time type of the instance referenced by e. If R and T are the same type, if R is a reference type and an implicit reference conversion from R to T exists, or if R is a value type and T is an interface type that is implemented by R, the result is true.
However, there seems to be something specific about enum types missing here. Assuming obj
is an instance of enum type MyEnum
none of the clauses matches the code above:
R and T are not the same type because R is
MyEnum
and T isSystem.Enum
.R is
MyEnum
which is a value type (11.1.9) and not a reference type.T is
System.Enum
which is not an interface type.
I don't want to claim that there is an error in the specification, but after a detailed reading of 14.9.10 I'm unable to see how is Enum
can evaluate to true given a boxed reference to an enum type.
Knowing that standards people in general are much smarter than I am I probably overlooked something, but even if I didn't this shouldn't stop you from using is Enum
to test if a type is an enum. I'm sure that it is not an implementation detail that it can used like this.