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.
Omari
0

Comments

1 comment

  • Omari
    Exception on decompiling.

    [url=code://SqlMetal:3.5.0.0:b03f5f7f11d50a3a/LinqToSqlShared.Generator.CodeGeneratorFactory.DbmlGenerator.GenerateMapping/VisitAssociation(LinqToSqlShared.DbmlObjectModel.Association]code://SqlMetal:3.5.0.0:b03f5f7f11d50a3 ... ssociation[/url]):LinqToSqlShared.DbmlObjectModel.Association
    Omari
    0

Add comment

Please sign in to leave a comment.