将INT值动态设置为Nullable枚举属性,而无需显式类型转换

时间:2019-02-11 09:24:23

标签: c# reflection enums nullable

我有一个将DataTable填充到简单DTO对象的方法。为了简化,我将使用以下示例:

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
}

以上抛出:

  

类型为'System.Int32'的对象不能转换为类型为'System.Nullable`1 [Test.Program + Gender]'。

如果我将MyGender声明为Gender(不是Nullable),则一切正常。

如果我使用显式Cast prop.SetValue(o, (Gender)intValue, null);

,它也可以工作

但是,我不想(也不能)使用显式强制类型转换:(Gender)intValue,因为我在创建代码时不了解底层的“硬”类型DTO对象。

我希望有类似(无法编译)的东西:

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

我也尝试过:

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

哪个抛出:

  

从'System.Int32'强制转换为   'System.Nullable`1 [[Test.Program + Gender ...]

我快死了。我有什么选择?

.NET Framework 4.6.2

2 个答案:

答案 0 :(得分:3)

这是我能想到的最好的方法。进行了明确检查,以查看分配给该属性是否可为空,但是我认为您不能避免这种情况。

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);
}

当然,如果所分配的属性不是枚举,则会发生不好的事情。 var convertedValue = enumType.IsEnum ? Enum.ToObject(enumType, intValue); : intValue;可以避免这种情况。

答案 1 :(得分:0)

要考虑的“创造性”选项是:

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

这看起来很奇怪,但是它确实起作用,因为常数 0具有内置的implicit cast枚举(其他数字没有)。

因此,将其设置为0,然后将其递增为您感兴趣的实际数字。这里的主要好处是您不会受到性能影响(和/或缺乏类型安全)。 您可能还想在代码中添加注释,说明执行原因。 ;)