Подтвердить что ты не робот

Как установить тип NULL с помощью кода отражения (С#)?

Мне нужно установить свойства класса с помощью отражения.

У меня есть Dictionary<string,string> с именами свойств и строковыми значениями.

Внутри цикла отражения мне нужно преобразовать значение строки в соответствующий тип свойства, задав значение для каждого свойства. Некоторые из этих типов свойств являются типами с нулевым значением.

  • Как узнать из PropertyInfo, если свойство является типом NULL?
  • Как установить тип с нулевым значением с помощью отражения?

изменить Первый метод, определенный в комментариях к этому блогу, кажется, тоже делает трюк: http://weblogs.asp.net/pjohnson/archive/2006/02/07/437631.aspx

4b9b3361

Ответ 1

  • Один из способов сделать это:

    type.GetGenericTypeDefinition() == typeof(Nullable<>)
    
  • Просто установите в соответствии с любым другим кодом отражения:

    propertyInfo.SetValue(yourObject, yourValue);
    

Ответ 2

Зачем вам нужно знать, является ли оно нулевым? И вы имеете в виду "ссылочный тип" или "Nullable<T>"?

В любом случае, со строковыми значениями, самым простым вариантом будет использование TypeConverter, которое более-легко (точнее) доступно на PropertyDescriptor:

PropertyDescriptorCollection props = TypeDescriptor.GetProperties(obj);
// then per property...
PropertyDescriptor prop = props[propName];
prop.SetValue(obj, prop.Converter.ConvertFromInvariantString(value));

Это должен использовать правильный конвертер, даже если он установлен для свойства (а не для каждого типа). Наконец, если вы делаете много этого, это позволяет ускорить с помощью HyperDescriptor без изменения кода (кроме того, чтобы включить его для тип, только один раз).

Ответ 3

В частности, чтобы преобразовать целое число в перечисление и присвоить свойство 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);
}

Ответ 4

Я создал небольшой образец. Если у вас есть какие-либо вопросы относительно этого кода, добавьте комментарии.

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

    }
}

Ответ 5

Первоначально наилучшее решение упоминается на форуме 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");
            }
            ...
        }
...
}

Ответ 6

Проверка на Nullable типов проста, int? на самом деле System.Nullable<System.Int32>. Поэтому вы просто проверяете, является ли тип типичным экземпляром System.Nullable<T>. Настройка не должна иметь значения, nullableProperty.SetValue(instance, null) или nullableProperty.SetValue(instance, 3)

Ответ 7

вот самое безопасное решение для типа объекта с нулевым значением

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

    }

Ответ 8

Я использовал следующее решение, избегая использования преобразователя типов для более эффективного управления кодом.

Я написал вспомогательный класс для поддержки операций

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