2

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?

Community
  • 1
  • 1
sq33G
  • 3,320
  • 1
  • 23
  • 38

4 Answers4

1

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 from System.Enum are available in any enum type. A boxing conversion exists from any enum type to System.Enum, and an unboxing conversion exists from System.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 type System.Enum inherits from the type System.ValueType, which, in turn, inherits from type object. At run-time, a value of type System.Enum can be null or a reference to a boxed value of any enum type.

Community
  • 1
  • 1
svick
  • 236,525
  • 50
  • 385
  • 514
0

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 than System.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 is System.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.

Martin Liversage
  • 104,481
  • 22
  • 209
  • 256
  • @leppie: Your assertion is true, but I'm not talking about the type `Enum`. I'm talking about enumerations and `typeof(MyEnumeration).IsValueType` is `true` for any `MyEnumeration` you define by the keyword `enum`. – Martin Liversage Feb 07 '12 at 13:48
  • But the question asks about `Enum`, not `MyEnum`. Did I read the question wrong? – leppie Feb 07 '12 at 13:50
  • I read this question as "where in the spec is it explained why `X is Enum == true` when `X` is an enumeration?" – Martin Liversage Feb 07 '12 at 13:59
  • I don't deny that an enumeration value can be cast to Enum - I'm asking how the bulleted list immediately after the paragraph you quote from the spec covers this case. Similarly, I don't see how it covers the case `3 is object`. – sq33G Feb 08 '12 at 10:37
  • In the ECMA version of the spec that you're using, the first bullet applies: there is a boxing conversion from any enum type to `Enum`. – svick Feb 08 '12 at 13:46
  • @svick: The compile time type of `obj` is `System.Object` so I don't see how the first bullet applies. If I understand the first bullet correctly the criteria can be evaluated at compile time, not run-time. – Martin Liversage Feb 08 '12 at 14:16
  • @MartinLiversage, you're right, I overlooked that. It seems it really is a bug in that version of the spec. C# 4 spec has it correctly, though. – svick Feb 08 '12 at 14:24
0

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.

Craig Wilson
  • 12,174
  • 3
  • 41
  • 45
  • Not quite. You just contradicted yourself :) – leppie Feb 07 '12 at 13:47
  • interesting... well, hmm... where is Eric Lippert... perhaps he can answer this question... – Craig Wilson Feb 07 '12 at 13:56
  • @leppie, there is no contradiction. `System.Enum` is an actual type. There is no such type for classes or structs. There is `System.ValueType`, but that is the base for all value types, not just structs. – svick Feb 08 '12 at 13:26
0

Enum is a reference type.

typeof(Enum).IsValueType => false

Interestingly,

typeof(ValueType).IsValueType => false
leppie
  • 115,091
  • 17
  • 196
  • 297
  • 1
    Yeah, I was just browsing the msdn site -> http://msdn.microsoft.com/en-us/library/system.enum.aspx. Enum inherits from ValueType, which inherits from Object. All of these are classes and therefore reference types. Apparently, there were some issues with .IsClass in frameworks prior to .NET 4 -> http://stackoverflow.com/questions/1661913/typeofsystem-enum-isclass-false. – Craig Wilson Feb 07 '12 at 14:05
  • @CraigWilson: Interesting 'bug'. 99.9% of the time I am only interested in `.IsValueType` :) – leppie Feb 07 '12 at 14:07