【问题标题】:Converting from String to <T>从字符串转换为 <T>
【发布时间】:2009-04-09 03:33:15
【问题描述】:

我真的应该能够得到这个,但我只是到了我认为更容易问的地步。

在 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>

【问题讨论】:

  • 您能否提供您尝试解析的 XML 示例
  • 想提供一个您期望得到的样本吗?在这种情况下,T 可以是很多东西......您将字符串转换为它们的能力将取决于您定义允许的内容的能力。

标签: c# xml generics


【解决方案1】:

我建议不要尝试自己解析 XML,而是尝试创建可以从 XML 反序列化到类中的类。我会强烈建议遵循本德威的回答。

但如果你不能做到这一点,那就有希望了。你可以使用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");

【讨论】:

  • 我会看到你的 +1 并再次提高你的 +1。虽然我对它的优雅感到困惑,但这闻起来像是为了泛型而使用泛型。
  • 让我们来讨论一下 GetValue() 与 (int)GetValue() 的美学:P
  • 序列化对于这个函数的预期用途来说是不可能的。起初我们考虑了 Xml poco,但是当 xml 达到 >1Mb 范围时,它会导致应用程序陷入困境。因此,xpath 是要走的路。
  • 这有效,但不适用于可空类型。检查this StackOverflow question 以获得解决方案。
【解决方案2】:

你可以大致这样开始:

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

如果您必须解析特殊类型的属性,例如颜色或文化字符串等,您当然必须在上面构建特殊情况。但这将处理您的大部分原始类型。

【讨论】:

  • 如果你使用 GetConverter(typeof(T)) 你不需要 t 变量或 new()
  • 是的,我很快就搞定了。也许我会给它一个编辑 - 谢谢。
【解决方案3】:

如果您决定采用 POCO(普通旧 CLR 对象)的序列化路线,那么很少有工具可以帮助您生成对象。

  • 您可以使用xsd.exe 根据您的 XML 定义生成 .cs 文件
  • WCF REST Starter Kit Preview 2 中有一个新功能,称为粘贴为 Html。这个功能真的很酷,可以让您在剪贴板中提取一段 HTML,然后当您将其粘贴到 cs 文件中时,它会自动将 xml 转换为 CLR 对象以进行序列化。

【讨论】:

  • 序列化对于这个函数的预期用途来说是不可能的。起初我们考虑了 Xml poco,但是当 xml 达到 >1Mb 范围时,它会导致应用程序陷入困境。老板说 xpath 是要走的路
  • LINQ to XML 比 xpath 更快。
  • 参见en.wikipedia.org/wiki/XML#Processing_files,XPath 使用 DOM,Linq to XML 使用“拉解析”
  • 请记住,我们中的一些人将在 .net 2.0 世界中停留一段时间...... :-)
  • 哎呀,我很抱歉听到这个消息。
【解决方案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 是您在其中注册类的某种字典。 (显然,需要进行一些检查以确保反序列化程序已在字典中注册)。

(在这种情况下, where T:new() 是无用的,因为您的方法不需要创建任何对象。

【讨论】:

  • 你不能在没有 where 类限制的泛型类型上使用 as 运算符。
  • 哎呀,不知道那个。我想你仍然可以进行常规演员阵容吗?
【解决方案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>");
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-15
    • 2011-08-19
    • 2014-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多