There is a bug in decompiling expressions with nullable enums.
Compile the code below and look at method TestEnumNullableValue and TestEnumNullableProperty in Reflector.
using System;
using System.Collections.Generic;
public enum SomeEnum
{
One,
Two
}
public class Foo
{
public SomeEnum EnumProperty { get; set; }
public SomeEnum? EnumNullableProperty { get; set; }
public int IntProperty { get; set; }
public int? IntNullableProperty { get; set; }
public DateTime? DateTimeNullableProperty { get; set; }
public Guid? GuidNullableProperty { get; set; }
}
public class MyClass
{
private static void TestEnumValue()
{
SomeEnum value = SomeEnum.Two;
if (value < SomeEnum.Two)
{
Console.WriteLine("<");
}
else
{
Console.WriteLine(">=");
}
if (value == SomeEnum.Two)
{
Console.WriteLine("==");
}
else
{
Console.WriteLine("!=");
}
}
private static void TestEnumNullableValue()
{
SomeEnum? value = null;
if (value < SomeEnum.Two)
{
Console.WriteLine("<");
}
else
{
Console.WriteLine("null || >=");
}
if (value == SomeEnum.Two)
{
Console.WriteLine("==");
}
else
{
Console.WriteLine("null || !=");
}
}
private static void TestEnumProperty()
{
Foo obj = new Foo();
if (obj.EnumProperty < SomeEnum.Two)
{
Console.WriteLine("<");
}
else
{
Console.WriteLine(">=");
}
if (obj.EnumProperty == SomeEnum.Two)
{
Console.WriteLine("==");
}
else
{
Console.WriteLine("!=");
}
}
private static void TestEnumNullableProperty()
{
Foo obj = new Foo();
if (obj.EnumNullableProperty < SomeEnum.Two)
{
Console.WriteLine("<");
}
else
{
Console.WriteLine("null || >=");
}
if (obj.EnumNullableProperty == SomeEnum.Two)
{
Console.WriteLine("==");
}
else
{
Console.WriteLine("null || !=");
}
}
private static void TestIntValue()
{
int value = 5;
if (value < 5)
{
Console.WriteLine("<");
}
else
{
Console.WriteLine(">=");
}
if (value == 5)
{
Console.WriteLine("==");
}
else
{
Console.WriteLine("!=");
}
}
private static void TestIntNullableValue()
{
int? value = null;
if (value < 5)
{
Console.WriteLine("<");
}
else
{
Console.WriteLine("null || >=");
}
if (value == 5)
{
Console.WriteLine("==");
}
else
{
Console.WriteLine("null || !=");
}
}
private static void TestIntProperty()
{
Foo obj = new Foo();
if (obj.IntProperty < 5)
{
Console.WriteLine("<");
}
else
{
Console.WriteLine(">=");
}
if (obj.IntProperty == 5)
{
Console.WriteLine("==");
}
else
{
Console.WriteLine("!=");
}
}
private static void TestIntNullableProperty()
{
Foo obj = new Foo();
if (obj.IntNullableProperty < 5)
{
Console.WriteLine("<");
}
else
{
Console.WriteLine("null || >=");
}
if (obj.IntNullableProperty == 5)
{
Console.WriteLine("==");
}
else
{
Console.WriteLine("null || !=");
}
}
private static void TestDateTimeNullableValue()
{
Foo obj = new Foo();
if (obj.DateTimeNullableProperty < DateTime.Now)
{
Console.WriteLine("<");
}
else
{
Console.WriteLine("null || >=");
}
if (obj.DateTimeNullableProperty == DateTime.Now)
{
Console.WriteLine("==");
}
else
{
Console.WriteLine("null || !=");
}
}
private static void TestGuidNullableValue()
{
Foo obj = new Foo();
if (obj.GuidNullableProperty == Guid.NewGuid())
{
Console.WriteLine("==");
}
else
{
Console.WriteLine("null || !=");
}
}
public static void Main()
{
TestEnumValue();
TestEnumNullableValue();
TestEnumProperty();
TestEnumNullableProperty();
TestIntValue();
TestIntNullableValue();
TestIntProperty();
TestIntNullableProperty();
}
}
Instead of:
if (obj.EnumNullableProperty < SomeEnum.Two)
{
Console.WriteLine("<");
}
else
{
Console.WriteLine("null || >=");
}
Reflector decompiles it as:
if (((SomeEnum) foo.EnumNullableProperty) < SomeEnum.Two)
{
Console.WriteLine("<");
}
else
{
Console.WriteLine("null || >=");
}
Semanticaly C# compiles original code as:
if (value.GetValueOrDefault() < SomeEnum.Two && value.HasValue)
{
Console.WriteLine("<");
}
else
{
Console.WriteLine("null || >=");
}
It is interestin that for complex value types (Guid, DateTime) C# evaluats GetValueOrDefault and HasValue in reverse order.
Compile the code below and look at method TestEnumNullableValue and TestEnumNullableProperty in Reflector.
Instead of:
if (obj.EnumNullableProperty < SomeEnum.Two)
{
Console.WriteLine("<");
}
else
{
Console.WriteLine("null || >=");
}
Reflector decompiles it as:
if (((SomeEnum) foo.EnumNullableProperty) < SomeEnum.Two)
{
Console.WriteLine("<");
}
else
{
Console.WriteLine("null || >=");
}
Semanticaly C# compiles original code as:
if (value.GetValueOrDefault() < SomeEnum.Two && value.HasValue)
{
Console.WriteLine("<");
}
else
{
Console.WriteLine("null || >=");
}
It is interestin that for complex value types (Guid, DateTime) C# evaluats GetValueOrDefault and HasValue in reverse order.