tags:

views:

2098

answers:

6

Need to set properties of a class via reflection.

I have a dictionary with property names and string values.

Inside a reflection loop - I need to convert the string value to appropriate property type while setting the value for each property. Some of these property types are nullable types.

  1. How to konw from PropertyInfo if the prop is a nullable type ?
  2. How to set a nullable type via reflection.

edit: The first method defined in the comments on this blog seems to do the trick as well: http://weblogs.asp.net/pjohnson/archive/2006/02/07/437631.aspx

A: 

Checking for Nullable types is easy, int? is actually System.Nullable<System.Int32>. So you just check if the type is a generic instance of System.Nullable<T>. Setting shouldn't make a difference, nullableProperty.SetValue(instance, null) or nullableProperty.SetValue(instance, 3)

+3  A: 
  1. One way to do this is:

    type.GetGenericTypeDefinition() == typeof(Nullable<>)

  2. Just set is as per any other reflection code:

    propertyInfo.SetValue(yourObject, yourValue);

HTH, Kent

Kent Boogaart
Your "1" will break for non-generic types; "Nullable.GetUnderlyingType(type) != null" is safer.
Marc Gravell
this works! "Nullable.GetUnderlyingType(type) != null"
dotnetcoder
Or just check type.IsGenericTypeDefinition first
Kent Boogaart
+4  A: 

Why do you need to know if it is nullable? And do you mean "reference-type", or "Nullable<T>"?

Either way, with string values, the easiest option would be via the TypeConverter, which is more-easily (and more accurately) available on PropertyDescriptor:

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

This should use the correct converter, even if set per-property (rather than per-type). Finally, if you are doing lots of this, this allows for acceleration via HyperDescriptor, without changing the code (other than to enable it for the type, done once only).

Marc Gravell
+1 for the answer. Greatly describe how to convert and set the values.Thanks Marc.
bugBurger
Well, as much as I hate converting my types to string, this worked for what I wanted. Thanks!
TravisWhidden
+2  A: 

I've created small sample. If you have any questions regarding this code, please add comments.

EDIT: updated sample based on great comment by Marc Gravell

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

    }
}
aku
Nullable.GetUnderlyingType would be easier; also, this won't follow any [TypeConverter(...)] instructions set at the property level, which might (depending on the scenario) be an issue.
Marc Gravell
good comment Marc, I agree that GetUnderlyingType would be a better solution.
aku
A: 

A link

YordanGeorgiev
A: 

Specifically to convert an integer to an enum and assign to a nullable enum property:

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