Ответ 1
-
Один из способов сделать это:
type.GetGenericTypeDefinition() == typeof(Nullable<>)
-
Просто установите в соответствии с любым другим кодом отражения:
propertyInfo.SetValue(yourObject, yourValue);
Мне нужно установить свойства класса с помощью отражения.
У меня есть Dictionary<string,string>
с именами свойств и строковыми значениями.
Внутри цикла отражения мне нужно преобразовать значение строки в соответствующий тип свойства, задав значение для каждого свойства. Некоторые из этих типов свойств являются типами с нулевым значением.
изменить Первый метод, определенный в комментариях к этому блогу, кажется, тоже делает трюк: http://weblogs.asp.net/pjohnson/archive/2006/02/07/437631.aspx
Один из способов сделать это:
type.GetGenericTypeDefinition() == typeof(Nullable<>)
Просто установите в соответствии с любым другим кодом отражения:
propertyInfo.SetValue(yourObject, yourValue);
Зачем вам нужно знать, является ли оно нулевым? И вы имеете в виду "ссылочный тип" или "Nullable<T>
"?
В любом случае, со строковыми значениями, самым простым вариантом будет использование TypeConverter
, которое более-легко (точнее) доступно на PropertyDescriptor
:
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(obj);
// then per property...
PropertyDescriptor prop = props[propName];
prop.SetValue(obj, prop.Converter.ConvertFromInvariantString(value));
Это должен использовать правильный конвертер, даже если он установлен для свойства (а не для каждого типа). Наконец, если вы делаете много этого, это позволяет ускорить с помощью HyperDescriptor
без изменения кода (кроме того, чтобы включить его для тип, только один раз).
В частности, чтобы преобразовать целое число в перечисление и присвоить свойство nullable enum:
int value = 4;
if(propertyInfo.PropertyType.IsGenericType
&& Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null
&& Nullable.GetUnderlyingType(propertyInfo.PropertyType).IsEnum)
{
var enumType = Nullable.GetUnderlyingType(propertyInfo.PropertyType);
var enumValue = Enum.ToObject(enumType, value);
propertyInfo.SetValue(item, enumValue, null);
//-- suggest by valamas
//propertyInfo.SetValue(item, (value == null ? null : enumValue), null);
}
Я создал небольшой образец. Если у вас есть какие-либо вопросы относительно этого кода, добавьте комментарии.
EDIT: обновленный образец, основанный на замечательном комментарии Марка Гравелла
class Program
{
public int? NullableProperty { get; set; }
static void Main(string[] args)
{
var value = "123";
var program = new Program();
var property = typeof(Program).GetProperty("NullableProperty");
var propertyDescriptors = TypeDescriptor.GetProperties(typeof(Program));
var propertyDescriptor = propertyDescriptors.Find("NullableProperty", false);
var underlyingType =
Nullable.GetUnderlyingType(propertyDescriptor.PropertyType);
if (underlyingType != null)
{
var converter = propertyDescriptor.Converter;
if (converter != null && converter.CanConvertFrom(typeof(string)))
{
var convertedValue = converter.ConvertFrom(value);
property.SetValue(program, convertedValue, null);
Console.WriteLine(program.NullableProperty);
}
}
}
}
Первоначально наилучшее решение упоминается на форуме MSDN. Однако, когда вам нужно внедрить динамическое решение, где вы точно не знаете, сколько объявляемых полей может быть объявлено в классе, лучше всего проверить, можно ли присвоить тип Nullable < > свойство, которое вы проверяете с помощью отражения
protected T initializeMe<T>(T entity, Value value)
{
Type eType = entity.GetType();
foreach (PropertyInfo pi in eType.GetProperties())
{
//get and nsame of the column in DataRow
Type valueType = pi.GetType();
if (value != System.DBNull.Value )
{
pi.SetValue(entity, value, null);
}
else if (valueType.IsGenericType && typeof(Nullable<>).IsAssignableFrom(valueType)) //checking if nullable can be assigned to proptety
{
pi.SetValue(entity, null, null);
}
else
{
System.Diagnostics.Trace.WriteLine("something here");
}
...
}
...
}
Проверка на Nullable типов проста, int? на самом деле System.Nullable<System.Int32>
.
Поэтому вы просто проверяете, является ли тип типичным экземпляром System.Nullable<T>
.
Настройка не должна иметь значения, nullableProperty.SetValue(instance, null)
или nullableProperty.SetValue(instance, 3)
вот самое безопасное решение для типа объекта с нулевым значением
if (reader[rName] != DBNull.Value)
{
PropertyInfo pi = (PropertyInfo)d[rName.ToLower()];
if (pi.PropertyType.FullName.ToLower().Contains("nullable"))
pi.SetValue(item, reader[rName]);
else
pi.SetValue(item, Convert.ChangeType(reader[rName], Type.GetType(pi.PropertyType.FullName)), null);
}
Я использовал следующее решение, избегая использования преобразователя типов для более эффективного управления кодом.
Я написал вспомогательный класс для поддержки операций
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Text;
public static class ObjectExtensions
{
/// <summary>
/// Enable using reflection for setting property value
/// on every object giving property name and value.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="target"></param>
/// <param name="propertyName"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool SetProperty<T>(this T target, string propertyName, object value)
{
PropertyInfo pi = target.GetType().GetProperty(propertyName);
if (pi == null)
{
Debug.Assert(false);
return false;
}
try
{
// Convert the value to set to the properly type
value = ConvertValue(pi.PropertyType, value);
// Set the value with the correct type
pi.SetValue(target, value, null);
}
catch (Exception ex)
{
Debug.Assert(false);
return false;
}
return true;
}
private static object ConvertValue(Type propertyType, object value)
{
// Check each type You need to handle
// In this way You have control on conversion operation, before assigning value
if (propertyType == typeof(int) ||
propertyType == typeof(int?))
{
int intValue;
if (int.TryParse(value.ToString(), out intValue))
value = intValue;
}
else if (propertyType == typeof(byte) ||
propertyType == typeof(byte?))
{
byte byteValue;
if (byte.TryParse(value.ToString(), out byteValue))
value = byteValue;
}
else if (propertyType == typeof(string))
{
value = value.ToString();
}
else
{
// Extend Your own handled types
Debug.Assert(false);
}
return value;
}
}
Примечание. Когда вы устанавливаете значение с нулевым значением (например, int?, Значение должно быть почти целочисленным или литерируемым типом. Вы не можете установить int в байт?. Итак, вам нужно правильно преобразовать. См. Код ConvertValue(), который проверяет либо для типа (int) и соответствующего типа NULL (int?))
Это код для установки значений с требуемой структурой данных. Словарь.
public class Entity
{
public string Name { get; set; }
public byte? Value { get; set; }
}
static void SetNullableWithReflection()
{
// Build array as requested
Dictionary<string, string> props = new Dictionary<string, string>();
props.Add("Name", "First name");
props.Add("Value", "1");
// The entity
Entity entity = new Entity();
// For each property to assign with a value
foreach (var item in props)
entity.SetProperty(item.Key, item.Value);
// Check result
Debug.Assert(entity.Name == "First name");
Debug.Assert(entity.Value == 1);
}