Преобразование из строки в <T> - PullRequest
56 голосов
/ 09 апреля 2009

Я действительно должен быть в состоянии получить это, но я просто до такой степени, что думаю, что было бы проще спросить.

В функции C #:

public static T GetValue<T>(String value) where T:new()
{
   //Magic happens here
}

Какая хорошая реализация для магии? Идея заключается в том, что у меня есть xml для разбора, а желаемые значения часто являются примитивами (bool, int, string и т. Д.), И это идеальное место для использования обобщений ... но простое решение ускользает от меня на данный момент .

кстати, вот пример xml, который мне нужно проанализировать

<Items>
    <item>
        <ItemType>PIANO</ItemType>
        <Name>A Yamaha piano</Name>
        <properties>
            <allowUpdates>false</allowUpdates>
            <allowCopy>true</allowCopy>
        </properties>   
    </item>
    <item>
        <ItemType>PIANO_BENCH</ItemType>
        <Name>A black piano bench</Name>
        <properties>
            <allowUpdates>true</allowUpdates>
            <allowCopy>false</allowCopy>
            <url>www.yamaha.com</url>
        </properties>
    </item>
    <item>
        <ItemType>DESK_LAMP</ItemType>
        <Name>A Verilux desk lamp</Name>
        <properties>
            <allowUpdates>true</allowUpdates>
            <allowCopy>true</allowCopy>
            <quantity>2</quantity>
        </properties>
    </item>
</Items>

Ответы [ 5 ]

150 голосов
/ 09 апреля 2009

Я бы предложил вместо того, чтобы пытаться анализировать XML самостоятельно, вы пытаетесь создать классы, которые десериализуются из XML в классы. Я бы настоятельно рекомендовал бы следовать ответу Бендевея.

Но если вы не можете сделать это, есть надежда. Вы можете использовать Convert.ChangeType.

public static T GetValue<T>(String value)
{
  return (T)Convert.ChangeType(value, typeof(T));
}

И пользуйся вот так

GetValue<int>("12"); // = 2
GetValue<DateTime>("12/12/98");
5 голосов
/ 09 апреля 2009

Вы можете начать с чего-то примерно такого:

TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
if (converter != null)
{
   return (T)converter.ConvertFrom(value);
}

Если вам нужно проанализировать атрибуты, которые являются особыми типами, например, цвета или культурные строки или еще что-то, вам, конечно, придется встроить особые случаи в вышеприведенное. Но это подойдет большинству ваших примитивных типов.

4 голосов
/ 09 апреля 2009

Если вы решите пойти по пути сериализации в POCO (Простой старый объект CLR), то существует несколько инструментов, которые могут помочь вам сгенерировать ваши объекты.

  • Вы можете использовать xsd.exe для создания файла .cs на основе вашего определения XML
  • В WCF REST Starter Kit Preview 2 появилась новая функция, которая называется Вставить как HTML. Эта функция действительно хороша и позволяет вам взять блок HTML, который находится в буфере обмена, а затем, когда вы вставляете его в файл cs, он автоматически преобразует XML в объект CLR для сериализации.
0 голосов
/ 09 апреля 2009

снова с оговоркой, что делать это, вероятно, плохая идея:

class Item 
{
    public string ItemType { get; set; }
    public string Name { get; set; }
}

public static T GetValue<T>(string xml) where T : new()
{
    var omgwtf = Activator.CreateInstance<T>();
    var xmlElement = XElement.Parse(xml);
    foreach (var child in xmlElement.Descendants())
    {
        var property = omgwtf.GetType().GetProperty(child.Name.LocalName);
        if (property != null) 
            property.SetValue(omgwtf, child.Value, null);
    }
    return omgwtf;
}

тестовый прогон:

static void Main(string[] args)
{
    Item piano = GetValue<Item>(@"
        <Item>
            <ItemType />
            <Name>A Yamaha Piano</Name>
            <Moose>asdf</Moose>
        </Item>");
}
0 голосов
/ 09 апреля 2009

Для правильной работы вашего универсального метода придется делегировать его фактическую работу выделенному классу.

Что-то вроде

private Dictionary<System.Type, IDeserializer> _Deserializers;
    public static T GetValue<T>(String value) where T:new()
    {
       return _Deserializers[typeof(T)].GetValue(value) as T;
    }

где _Deserializers - это своего рода словарь, в котором вы регистрируете свои классы. (очевидно, потребуется некоторая проверка, чтобы убедиться, что десериализатор зарегистрирован в словаре).

(В этом случае метод where T: new () бесполезен, поскольку вашему методу не нужно создавать какой-либо объект.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...