bavaza
bavaza

Reputation: 11047

C# Parse string to type known at runtime

I have a file holding some of the variables of a class, and each line is a pair : variable, value. I'm looking for a way to load these at runtime (a-la XmlSerializer), using reflection.

Is there a way to parse a string into a Type known only at runtime?

The following is a wishful code sample where the last line (with the pi.SetValue() is not correct, because PropertyType is of class Type which does not have a generic Parse() method.

using (var sr = new StreamReader(settingsFileName))
{
    String  line;
    while ((line = sr.ReadLine()) != null)
    {
        String[] configValueStrs = line.Trim().Split(seps);

        PropertyInfo pi = configurableProperties
                .Single(p => p.Name == configValueStrs[0].Trim());

        //How do I manage this?
        pi.SetValue(this, pi.PropertyType.Parse(configValueStrs[1].Trim()), null);
     }
 }

Since all of the relevant variables are Ints, Doubles, Strings or Booleans, as a last resort, I can Switch on the type and use the corresponding ToType() method, but I bet there is a more elegant solution.

Upvotes: 24

Views: 27920

Answers (6)

cdiggins
cdiggins

Reputation: 18203

Here is what I consider to be a cleaner implementation of the answer from Scott Hanselman via Russell Troywest

   public static object Parse(Type t, string s)
      => TypeDescriptor.GetConverter(t).ConvertFromInvariantString(s);

   public static T Parse<T>(string s)
      => (T)Parse(typeof(T), s);

Upvotes: 0

quicktrick
quicktrick

Reputation: 112

I had the same task to load variables of a class, using reflection. I load key/value pair strings from a file, then I parse the values basing on corresponding key variables' definitions from my settings class.

Briefly, I use the following code (method FieldInfo.SetValue (Object, Object) is the key here, because it doesn't require any type conversion of the Object value, returned by TypeConverter.ConvertFromString method):

using System.Reflection;
using System.ComponentModel;
using System.Globalization;

....

Settings settings = new Settings();   // my Settings class with variables to load
FieldInfo[] fields = settings.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static);
....

foreach (var field in fields)
{
    if (key.KeyName == field.Name)
    {
        try
        {
            field.SetValue(settings, TypeDescriptor.GetConverter(field.FieldType).ConvertFromString(null, CultureInfo.InvariantCulture, key.Value));
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error: The value string \"{0}\" isn't parsed!", key.Value);
            //Console.WriteLine(ex.ToString());
        } 
        break;
    }
}

Upvotes: -1

rene
rene

Reputation: 42444

You can use the static Convert.ChangeType method for that. It takes an object as its first parameter and a Type instance you want to convert the object to. The return value is of the type you requested or null if no suitable conversion was found. This method throw 4 different exceptions, from which three are caused by the value it tries to convert. You might want to catch and handle these.

Use the function as follows in your example:

// Convert.ChangeType can throw if the string doesn't convert to any known type
    pi.SetValue(this
      , Convert.ChangeType(configValueStrs[1], pi.PropertyType) 
      , null); 

Upvotes: 16

Russell Troywest
Russell Troywest

Reputation: 8776

TypeConverters are the way to go. Take a look here for a good example of what to do.

Nicked straight from hanselmans blog:

public static T GetTfromString<T>(string mystring)
{
   var foo = TypeDescriptor.GetConverter(typeof(T));
   return (T)(foo.ConvertFromInvariantString(mystring));
}

Upvotes: 44

Xcalibur37
Xcalibur37

Reputation: 2323

I would recommend using MethodInfo on the property for the Parse method and see if the MethodInfo object is valid. Then, carry out the parse operation if valid.

http://msdn.microsoft.com/en-us/library/system.reflection.methodinfo.aspx

Upvotes: 0

Bradley Uffner
Bradley Uffner

Reputation: 16991

I believe that TypeConverters, Specifically StringConverter can help you with this problem.

http://msdn.microsoft.com/en-us/library/system.componentmodel.stringconverter.aspx

Upvotes: 2

Related Questions