C # Разбор строки для ввода типа, известного во время выполнения - PullRequest
13 голосов
/ 24 декабря 2011

У меня есть файл, содержащий некоторые переменные класса, и каждая строка представляет собой пару: переменная, значение . Я ищу способ загрузить их во время выполнения (а-ля 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(), но держу пари, что есть более элегантное решение.

Ответы [ 5 ]

24 голосов
/ 24 декабря 2011

TypeConverters это путь.Посмотрите здесь , чтобы найти хороший пример того, что делать.

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

public static T GetTfromString<T>(string mystring)
{
   var foo = TypeDescriptor.GetConverter(typeof(T));
   return (T)(foo.ConvertFromInvariantString(mystring));
}
7 голосов
/ 24 декабря 2011

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

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

// 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 голосов
/ 24 декабря 2011

Я считаю, что TypeConverters, в частности StringConverter может помочь вам с этой проблемой.

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

0 голосов
/ 05 сентября 2016

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

Вкратце, я использую следующий код (здесь ключом является метод 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;
    }
}
0 голосов
/ 24 декабря 2011

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

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

...