Динамически установить значение INT в Nullable enum свойство без явного приведения типа
У меня есть метод, который заполняет 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) все работает отлично.
Это также работает, если я использую явное приведение 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 ответа
Это лучшее, что я могу придумать. Существует явная проверка, чтобы определить, является ли присваиваемое свойство обнуляемым, но я не думаю, что вы можете избежать этого.
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;
бы избежать этого, если бы вам это было нужно.
"Творческий" вариант для рассмотрения:
var o = new Person();
o.MyGender = 0;
o.MyGender += intValue;
Это выглядит странно, но это работает, так как константа 0 имеет встроенное неявное приведение к enum (чего нет у других чисел).
Таким образом, вы устанавливаете его на 0, а затем увеличиваете его до фактического числа, которое вас интересует. Ключевое преимущество здесь заключается в том, что вы не берете удар по производительности (и / или отсутствие безопасности типов) при использовании отражения. Возможно, вы захотите добавить комментарий к коду относительно того, почему вы это делаете. ;)