26

Alternative Title: Dynamically convert to a type at runtime.

I want to to convert an Object to a type that will be assigned at runtime.

For example, assume that I have a function that assigns a string value(from a TextBox or Dropdownlist) to an Object.Property.

How would I convert the value to proper type? For instance, it could be an integer, string, or enum.

Public void Foo(object obj,string propertyName,object value)
{
  //Getting type of the property og object.
  Type t= obj.GetType().GetProperty(propName).PropertyType;

  //Now Setting the property to the value .
  //But it raise an error,because sometimes type is int and value is "2"
  //or type is enum (e.a: Gender.Male) and value is "Male"
  //Suppose that always the cast is valid("2" can be converted to int 2)

  obj.GetType().GetProperty(propName).SetValue(obj, value, null);
}
nAviD
  • 2,784
  • 1
  • 33
  • 54

5 Answers5

47

You need to use the Convert.ChangeType(...) function [note: in the function below, the input propertyValue could just as easily have been of type object ... I just had a string version pre-baked]:

/// <summary>
/// Sets a value in an object, used to hide all the logic that goes into
///     handling this sort of thing, so that is works elegantly in a single line.
/// </summary>
/// <param name="target"></param>
/// <param name="propertyName"></param>
/// <param name="propertyValue"></param>
public static void SetPropertyValueFromString(this object target,               
                              string propertyName, string propertyValue)
{
    PropertyInfo oProp = target.GetType().GetProperty(propertyName);
    Type tProp = oProp.PropertyType;

    //Nullable properties have to be treated differently, since we 
    //  use their underlying property to set the value in the object
    if (tProp.IsGenericType
        && tProp.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
    {
        //if it's null, just set the value from the reserved word null, and return
        if (propertyValue == null)
        {
            oProp.SetValue(target, null, null);
            return;
        }

        //Get the underlying type property instead of the nullable generic
        tProp = new NullableConverter(oProp.PropertyType).UnderlyingType;
    }

    //use the converter to get the correct value
    oProp.SetValue(target, Convert.ChangeType(propertyValue, tProp), null);
}
fordareh
  • 2,923
  • 2
  • 26
  • 39
  • The only downside to this approach is that it won't work on nullable types. – James Johnson Sep 30 '11 at 21:46
  • Just noticed that you do have some logic in there for nullable types. – James Johnson Sep 30 '11 at 22:02
  • Convert.ChangeType() is satisfying although I should do some checking for enums , tnx fordareh. – nAviD Sep 30 '11 at 22:10
  • 1
    Is there a difference between `new NullableConverter(oProp.PropertyType).UnderlyingType` and `Nullable.GetUnderylingType(oProp.PropertyType)`? I assume the latter is just newer. – Manuzor Sep 06 '17 at 13:21
  • 1
    @Manuzor - It looks like they've both been around since .NET 2.0, but I think you're right to note that the instantiation overhead of the NullableConverter (though minimal) probably isn't necessary in this case. In fact, I wasn't aware of the Nullable.GetUnderylingType method. Thanks for the heads up! – fordareh Sep 07 '17 at 15:21
2

A universal Type Converter is what you seek !? Not an easy feat..

Try this approach:

Universal Type Converter

You can in NuGet Install-Package UniversalTypeConverter

Also, is using Generics out of the question here? It would facilitate the solution if you know at least the target type of the conversion.

Michael Freidgeim
  • 26,542
  • 16
  • 152
  • 170
Anas Karkoukli
  • 1,342
  • 8
  • 13
1

Here's another way you can do it, but I'm not sure

Without support for generic types:

public void Foo(object obj,string propertyName,object value) 
{ 
    //Getting type of the property og object. 
    Type type = obj.GetType().GetProperty(propertyName).PropertyType;

    obj.GetType().GetProperty(propertyName).SetValue(obj, Activator.CreateInstance(type, value), null);
} 

With support for generic types:

public void Foo(object obj,string propertyName,object value) 
{ 
    //Getting type of the property og object. 
    Type type = obj.GetType().GetProperty(propertyName).PropertyType;

    if (type.IsGenericType)
        type = type.GetGenericArguments()[0];

    obj.GetType().GetProperty(propertyName).SetValue(obj, Activator.CreateInstance(type, value), null);
} 
James Johnson
  • 45,496
  • 8
  • 73
  • 110
0

I used the Convert function in C#. The way I'm doing my conversion is using reflection.:

Type type = this.myObject.GetType();

if (type.Name == "MyObjectClass") {
var Voucherrequest = (MyObjectClass)Convert.ChangeType(myObject, typeof(MyObjectClass));

This is all assuming you know what type you want to convert into. You can even make a switch and have multiple types you want to reflect too.

JEuvin
  • 866
  • 1
  • 12
  • 31
0

I'm not sure it works, but give it a try:

public static T To<T>(this IConvertible obj)
{
  return (T)Convert.ChangeType(obj, typeof(T));
}

Public void Foo(object obj,string propertyName,object value)
{
    Type t= obj.GetType().GetProperty(propName).PropertyType;
    obj.GetType().GetProperty(propName).SetValue(obj, value.To<t>(), null);
}
Marco
  • 56,740
  • 14
  • 129
  • 152
  • It doesn't work, because generic type t in To() must be defined in compile time . – nAviD Sep 30 '11 at 22:08
  • @Navid: no, because of the extension method I put at the beginning of my answer. I'm quite sure it will be evaluated at runtime... – Marco Sep 30 '11 at 22:10
  • I can say for a fact that this does not work and that @Navid is correct. Generic methods need the type to be provided at compile time – workabyte Aug 07 '15 at 14:13