HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Setting the value of properties via reflection

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
reflectionthepropertiesvaluesettingvia

Problem

I am working on an application in which I have to parse an XML file. Nodes of the XML file corresponds to an object. I have to populate the properties of the objects at run time. The code below queries the metadata of property and sets its value. Is there a better way to do it or is there a better way to map the elements of an XML to an object?

```
public static void SetPropertyValue(object obj, string propertyName, object propertyValue)
{
if (obj == null || string.IsNullOrWhiteSpace(propertyName))
{
return;
}

Type objectType = obj.GetType();

PropertyInfo propertyDetail = GetPropertyInfo(objectType, propertyName);

if (propertyDetail != null && propertyDetail.CanWrite)
{
Type propertyType = propertyDetail.PropertyType;

Type dataType = propertyType;

// Check for nullable types
if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
// Check for null or empty string value.
if (propertyValue == null || string.IsNullOrWhiteSpace(propertyValue.ToString()))
{
propertyDetail.SetValue(obj, null);
return;
}
else
{
dataType = propertyType.GetGenericArguments()[0];
}
}

if (dataType.Equals(typeof(int)))
{
propertyValue = Convert.ToInt32(propertyValue);
}

if (dataType.Equals(typeof(long)))
{
propertyValue = Convert.ToInt64(propertyValue);
}

if (dataType.Equals(typeof(short)))
{
propertyValue = Convert.ToInt16(propertyValue);
}

if (dataType.Equals(typeof(bool)))
{
string stringPropertyValue = propertyValue.ToString();

Solution

You can use reflection to parse some common .Net types:

public static object Parse(Type type, string str)
{
    try
    {
        var parse = type.GetMethod("Parse", new[] {typeof(string)});
        if (parse == null) throw new NotSupportedException();
        return parse.Invoke(null, new object[] { str });
    }
    //or don't catch
    catch (Exception)
    {
        return null;
    }
}


It will basically allow you to replace this code:

if (dataType.Equals(typeof(float)))
        {
            propertyValue = Convert.ToSingle(propertyValue);
        }

        if (dataType.Equals(typeof(double)))
        {
            propertyValue = Convert.ToDouble(propertyValue);
        }

        if (dataType.Equals(typeof(decimal)))
        {
            propertyValue = Convert.ToDecimal(propertyValue);
        }

        if (dataType.Equals(typeof(byte)))
        {
            propertyValue = Convert.ToByte(propertyValue);
        }

        if (dataType.Equals(typeof(string)))
        {
            propertyValue = Convert.ToString(propertyValue);
        }

        if (dataType.Equals(typeof(char)))
        {
            propertyValue = Convert.ToChar(propertyValue);
        }

        if (dataType.Equals(typeof(int)))
        {
            propertyValue = Convert.ToInt32(propertyValue);
        }

        if (dataType.Equals(typeof(long)))
        {
            propertyValue = Convert.ToInt64(propertyValue);
        }

        if (dataType.Equals(typeof(short)))
        {
            propertyValue = Convert.ToInt16(propertyValue);
        }


with this line:

propertyValue = Parse(dataType, propertyValue.ToString());


It will work for every other class, that has public static void Parse(string) method declared (most standart value types do). You can add Parse(string) method to your own classes, to make them support this kind of deserialization. You can also modify the above code to use Parse(string, IFormatProvider) instead, to avoid parsing issues related to different decimal separators in different cultures.

Code Snippets

public static object Parse(Type type, string str)
{
    try
    {
        var parse = type.GetMethod("Parse", new[] {typeof(string)});
        if (parse == null) throw new NotSupportedException();
        return parse.Invoke(null, new object[] { str });
    }
    //or don't catch
    catch (Exception)
    {
        return null;
    }
}
if (dataType.Equals(typeof(float)))
        {
            propertyValue = Convert.ToSingle(propertyValue);
        }

        if (dataType.Equals(typeof(double)))
        {
            propertyValue = Convert.ToDouble(propertyValue);
        }

        if (dataType.Equals(typeof(decimal)))
        {
            propertyValue = Convert.ToDecimal(propertyValue);
        }

        if (dataType.Equals(typeof(byte)))
        {
            propertyValue = Convert.ToByte(propertyValue);
        }

        if (dataType.Equals(typeof(string)))
        {
            propertyValue = Convert.ToString(propertyValue);
        }

        if (dataType.Equals(typeof(char)))
        {
            propertyValue = Convert.ToChar(propertyValue);
        }

        if (dataType.Equals(typeof(int)))
        {
            propertyValue = Convert.ToInt32(propertyValue);
        }

        if (dataType.Equals(typeof(long)))
        {
            propertyValue = Convert.ToInt64(propertyValue);
        }

        if (dataType.Equals(typeof(short)))
        {
            propertyValue = Convert.ToInt16(propertyValue);
        }
propertyValue = Parse(dataType, propertyValue.ToString());

Context

StackExchange Code Review Q#102289, answer score: 4

Revisions (0)

No revisions yet.