Установить свойство Nullable <> отражением

Я пытаюсь установить свойство Nullable < > динамически.

Получаю свое свойство ex:

PropertyInfo property = class.GetProperty("PropertyName"); // My property is Nullable<> at this time So the type could be a string or int

Я хочу установить свое свойство отражением, например

property.SetValue(class,"1256",null);

Он не работает, когда мое свойство является Nullable < > Generic. Поэтому я пытаюсь найти способ установить мое свойство.

Чтобы узнать тип моего свойства nullable < > i, выполните

Nullable.GetUnderlyingType(property.PropertyType)

Любая идея?

  • Я пытаюсь создать экземпляр моего свойства Nullable < > с помощью

    var nullVar = Activator.CreateInstance(typeof (Nullable < > ). MakeGenericType (новый тип [] {Nullable.GetUnderlyingType(свойство .PropertyType)}));

Но nullVar всегда Null

Ответ 1

Если вы хотите преобразовать произвольную строку в базовый тип Nullable, вы можете использовать класс Convert:

var propertyInfo = typeof(Foo).GetProperty("Bar");
object convertedValue = null;
try 
{ 
    convertedValue = System.Convert.ChangeType("1256", 
        Nullable.GetUnderlyingType(propertyInfo.PropertyType));
} 
catch (InvalidCastException)
{
    // the input string could not be converted to the target type - abort
    return;
}
propertyInfo.SetValue(fooInstance, convertedValue, null);

Этот пример будет работать, если целевой тип - это int, short, long (или неподписанные варианты, так как строка ввода представляет собой неотрицательное число), double, float или decimal. Предостережение: это не быстрый код.

Ответ 2

Если это nullable int, вам нужно использовать параметр int, а не строку.

 property.SetValue(klass,1256,null);

Обратите внимание на изменение класса, а не класса, поскольку класс является зарезервированным ключевым словом. Вы также можете использовать @class, если это абсолютно необходимо (цитируя его).

Если ваше свойство является общим, тогда, я думаю, вам, вероятно, понадобится использовать Convert для преобразования того, что у вас есть, что вам нужно.

 var nullType = Nullable.GetUnderlyingType(property.PropertyType)
 var value = Convert.ChangeType("1256", nullType );
 property.SetValue(klass, value, null );

Ответ 3

Вот полный пример, показывающий, как это сделать:

using System;
using System.Reflection;

class Test
{
    static void Main()
    {
        Foo foo = new Foo();
        typeof(Foo).GetProperty("Bar")
            .SetValue(foo, 1234, null);
    }
}

class Foo
{
    public Nullable<Int32> Bar { get; set; }
}

Как уже упоминалось, вам нужно передать правильный тип функции SetValue, но ваш другой код отражения не совсем прав. Вам нужно получить тип рассматриваемого класса, прежде чем вы сможете запросить его членов.

Изменить: Если я правильно понимаю, вы пытаетесь установить строковое значение для любого свойства с помощью отражения. Чтобы сделать это, вам нужно будет провести проверку типов и преобразование типов.

Вот пример того, что я имею в виду:

using System;
using System.Reflection;

class Test
{
    static void Main()
    {
        Foo foo = new Foo();

        PropertyInfo property = typeof(Foo).GetProperty("Bar");
        Object value =
            Convert.ChangeType("1234",
                Nullable.GetUnderlyingType(property.PropertyType)
                ?? property.PropertyType);

        property.SetValue(foo, value, null);
    }
}

class Foo
{
    public Nullable<Int32> Bar { get; set; }
}

Этот подход можно безопасно использовать независимо от того, является ли это свойство Nullable<>.

Ответ 4

"1256" - это строка, а не int.

Ответ 5

Я столкнулся с этой же проблемой, а также с проблемой с Convert.ChangeType, которая не обрабатывает DateTimes на Nullables, поэтому я объединил пару решений stackoverflow с некоторой динамической магией .NET 4, чтобы получить что-то, что я думаю, немного сладкое. Если вы посмотрите на код, мы используем dynamic для ввода объекта в Nullable во время выполнения, тогда время выполнения рассматривает его по-разному и позволяет присвоения базового типа объекту с нулевым значением.

public void GenericMapField(object targetObj, string fieldName, object fieldValue)
{
    PropertyInfo prop = targetObj.GetType().GetProperty(fieldName);
    if (prop != null)
    {
        if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
        {
            dynamic objValue = System.Activator.CreateInstance(prop.PropertyType);
            objValue = fieldValue;
            prop.SetValue(targetObj, (object)objValue, null);
        }
        else
        {
            prop.SetValue(targetObj, fieldValue, null);
        }
    }
}

Ответ 6

public static void SetValue(object target, string propertyName, object value)
{
  if (target == null)
    return;

  PropertyInfo propertyInfo = target.GetType().GetProperty(propertyName);

  object convertedValue = value;
  if (value != null && value.GetType() != propertyInfo.PropertyType)
  {
    Type propertyType = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType;
    convertedValue = Convert.ChangeType(value, propertyType);
  }

  propertyInfo.SetValue(target, convertedValue, null);
}