在没有显式类型转换的情况下将 INT 值动态设置为 Nullable enum 属性
Dynamically set INT value to Nullable enum property without explicit type cast
我有一个方法可以将 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
}
以上抛出:
Object of type 'System.Int32' cannot be converted to type 'System.Nullable`1[Test.Program+Gender]'.
如果我将 MyGender
声明为 Gender
(不可为空),则一切正常。
如果我使用显式 Cast,它也有效 prop.SetValue(o, (Gender)intValue, null);
但是,我不想(也不能)使用显式转换:(Gender)intValue
因为我不了解底层 "hard" 创建 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);
抛出:
Invalid cast from 'System.Int32' to
'System.Nullable`1[[Test.Program+Gender...]
我走投无路了。我有什么选择?
.NET Framework 4.6.2
这是我能想到的最好的。有一个显式检查以查看分配给的 属性 是否可为空,但我认为您无法避免这种情况。
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;
会避免这种情况。
要考虑的 "creative" 选项是:
var o = new Person();
o.MyGender = 0;
o.MyGender += intValue;
这看起来很奇怪,但它确实有效,因为 constant 0 有一个内置的 implicit cast 来枚举(其他数字没有)。
因此,您将其设置为 0,然后将其递增到您感兴趣的 实际 数字。这里的一个主要好处是您不会受到性能影响(和/或缺乏类型安全)使用反射。 您可能还想在代码中添加注释,说明您为什么这样做。 ;)
我有一个方法可以将 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
}
以上抛出:
Object of type 'System.Int32' cannot be converted to type 'System.Nullable`1[Test.Program+Gender]'.
如果我将 MyGender
声明为 Gender
(不可为空),则一切正常。
如果我使用显式 Cast,它也有效 prop.SetValue(o, (Gender)intValue, null);
但是,我不想(也不能)使用显式转换:(Gender)intValue
因为我不了解底层 "hard" 创建 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);
抛出:
Invalid cast from 'System.Int32' to 'System.Nullable`1[[Test.Program+Gender...]
我走投无路了。我有什么选择?
.NET Framework 4.6.2
这是我能想到的最好的。有一个显式检查以查看分配给的 属性 是否可为空,但我认为您无法避免这种情况。
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;
会避免这种情况。
要考虑的 "creative" 选项是:
var o = new Person();
o.MyGender = 0;
o.MyGender += intValue;
这看起来很奇怪,但它确实有效,因为 constant 0 有一个内置的 implicit cast 来枚举(其他数字没有)。
因此,您将其设置为 0,然后将其递增到您感兴趣的 实际 数字。这里的一个主要好处是您不会受到性能影响(和/或缺乏类型安全)使用反射。 您可能还想在代码中添加注释,说明您为什么这样做。 ;)