2

I have a method that populates a DataTable to simple DTO object. To simplify I'll use this example:

public enum Gender : int
{
    Male = 1,
    Female = 2
}

public class Person
{
    //...
    public Gender? MyGender { get; set; }
}

static void Main(string[] args)
{
    int intValue = 2; // value from DB

    var o = new Person();
    var prop = o.GetType().GetProperty("MyGender");    
    prop.SetValue(o, intValue , null); // <- Exception
}

The above throws:

Object of type 'System.Int32' cannot be converted to type 'System.Nullable`1[Test.Program+Gender]'.

If I declare MyGender as Gender (not Nullable) everything works fine.

It also works if I use an explicit Cast prop.SetValue(o, (Gender)intValue, null);

BUT, I don't want to (and can't) use the explicit cast: (Gender)intValue because I have no knowledge of the underlying "hard" type when I create the DTO object .

I was hoping for something like (which dose not compile):

var propType = prop.PropertyType;
prop.SetValue(o, (propType)intValue, null);

I also tried:

public static dynamic Cast(dynamic obj, Type castTo)
{
    return Convert.ChangeType(obj, castTo);
}    
var propType = prop.PropertyType;
prop.SetValue(o, Cast(intValue, propType), null);

Which throws:

Invalid cast from 'System.Int32' to 'System.Nullable`1[[Test.Program+Gender...]

I am at dead end. what are my options?

.NET Framework 4.6.2

zig
  • 4,524
  • 1
  • 24
  • 68

2 Answers2

3

This is the best I can come up with. There's an explicit check to see whether the property being assigned to is nullable, but I don't think you can avoid that.

public static void Main(string[] args)
{
    int intValue = 2; // value from DB

    var o = new Person();
    var prop = o.GetType().GetProperty("MyGender");   

    // Check whether the property is a nullable. If it is, get the type of underling enum
    // Otherwise, get the type of the enum directly from the property
    var enumType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
    // Convert the int to the enum type
    var convertedValue = Enum.ToObject(enumType, intValue);

    prop.SetValue(o, convertedValue , null);
}

Of course, bad things will happen if the property being assigned isn't an enum. var convertedValue = enumType.IsEnum ? Enum.ToObject(enumType, intValue); : intValue; would avoid that, if you needed it.

canton7
  • 37,633
  • 3
  • 64
  • 77
1

A "creative" option to consider is:

var o = new Person();
o.MyGender = 0;
o.MyGender += intValue;

This looks odd, but it does work since the constant 0 has a built-in implicit cast to enum (which other numbers do not).

So, you set it to 0, and then increment it to the actual number you are interested in. A key benefit here is you don't take the performance hit (and / or lack of type safety) of using reflection. You may want to add a comment to the code as to why you are doing it as well. ;)

mjwills
  • 23,389
  • 6
  • 40
  • 63