С# Строка описания для типа, известная во время выполнения

У меня есть файл, содержащий некоторые из переменных класса, и каждая строка представляет собой пару: variable, value. Я ищу способ загрузить их во время выполнения (a-la XmlSerializer), используя отражение.

Есть ли способ проанализировать string в Type, который известен только во время выполнения?

Ниже приведен пример желаемого кода, в котором последняя строка (с pi.SetValue() неверна, поскольку PropertyType имеет класс Type, который не имеет общего метода Parse().

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

Поскольку все соответствующие переменные являются Ints, Doubles, Strings или Booleans, в качестве последнего средства, я могу включить тип и использовать соответствующий метод ToType(), но я уверен, что есть более элегантное решение.

Ответ 1

Для этого можно использовать статический метод Convert.ChangeType. Он принимает в качестве первого параметра объект и Type экземпляр, в который вы хотите преобразовать объект. Возвращаемое значение относится к типу, который вы запросили, или null, если подходящее преобразование не найдено. Этот метод выдает четыре разных исключения, из которых три вызваны значением, которое он пытается преобразовать. Вы можете захотеть поймать и обработать их.

Используйте следующую функцию в своем примере:

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

Ответ 2

TypeConverters - это путь. Посмотрите here для хорошего примера того, что делать.

Ник прямо из блога hanselmans:

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

Ответ 4

Я бы рекомендовал использовать MethodInfo для свойства для метода Parse и посмотреть, действительно ли объект MethodInfo. Затем выполните операцию анализа, если она действительна.

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

Ответ 5

У меня была та же задача загрузить переменные класса, используя отражение. Я загружаю строки пары ключ/значение из файла, затем анализирую значения, основываясь на определениях ключевых переменных ключей из моего класса настроек.

Вкратце, я использую следующий код (метод FieldInfo.SetValue (Object, Object) - это ключ здесь, потому что он не требует какого-либо преобразования типа значения Object, возвращаемого методом TypeConverter.ConvertFromString):

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