Преобразование из строки в <T>
Я действительно должен быть в состоянии получить это, но я просто до такой степени, что, думаю, будет легче спросить.
В функции С#:
public static T GetValue<T>(String value) where T:new()
{
//Magic happens here
}
Какая хорошая реализация для магии? Идея заключается в том, что у меня есть xml для синтаксического анализа и требуемые значения часто являются примитивами (bool, int, string и т.д.), И это идеальное место для использования дженериков... но простое решение ускользает от меня в настоящий момент.
btw, здесь образец 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>
Ответы
Ответ 1
Я бы предложил вместо того, чтобы пытаться анализировать XML самостоятельно, вы пытаетесь создать классы, которые будут десериализовываться из XML в классы. Я настоятельно рекомендую следующий ответ Bendewey.
Но если вы не можете сделать это, есть надежда. Вы можете использовать Convert.ChangeType
.
public static T GetValue<T>(String value)
{
return (T)Convert.ChangeType(value, typeof(T));
}
И использовать так
GetValue<int>("12"); // = 12
GetValue<DateTime>("12/12/98");
Ответ 2
Вы можете начать с примерно примерно так:
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
if (converter != null)
{
return (T)converter.ConvertFrom(value);
}
Если вам нужно разбирать атрибуты, которые являются особыми типами, например цветами или строками культуры или еще что-то, вам, конечно же, придется создавать особые случаи в приведенном выше. Но это будет обрабатывать большинство ваших примитивных типов.
Ответ 3
Если вы решите пойти по пути сериализации в POCO (обычный старый объект CLR), тогда есть несколько инструментов, которые могут помочь вам сгенерировать ваши объекты.
- Вы можете использовать xsd.exe для создания файла .cs на основе вашего определения XML
- В появилась новая функция: просмотр WCF REST Starter Kit Preview 2, называемый Paste as Html. Эта функция действительно классная и позволяет вам взять блок HTML, который находится в вашем буфере обмена, а затем, когда вы вставляете его в файл cs, он автоматически преобразует xml в объект CLR для сериализации.
Ответ 4
Чтобы это правильно работало, ваш общий метод должен будет делегировать свою фактическую работу в выделенный класс.
Что-то вроде
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 - это своего рода словарь, в котором вы регистрируете свои классы. (очевидно, потребуется некоторая проверка, чтобы гарантировать, что десериализатор зарегистрирован в словаре).
(В этом случае, где T: new() бесполезно, потому что вашему методу не нужно создавать какой-либо объект.
Ответ 5
снова с оговоркой, что делать это, вероятно, плохая идея:
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>");
}