如何使用泛型函数将字符串值解析为自定义类型

时间:2016-02-23 19:22:54

标签: c# xml parsing generics

我正在尝试编写一个类来解析带有值字符串的XML配置文件到相应的值和类型。配置的示例条目是:

a<?php
$query = "SELECT * FROM aliases where client_id='$userid' ORDER BY time_edit DESC";
$result = mysql_query($query);
if ($result->num_rows > 0) {
    echo "<table border=1>";
    echo "<tr align=center>";
    echo "<th width=25%>Alias</th>";
    echo "<th width=25%>Times Used</th>";
    echo "<th width=25%>First Used</th>";
    echo "<th width=25%>Last Used</th>";
    echo "</tr>";
    echo "<tr><td>No Results</td></tr>";
}
    echo "<table border=1>";
    echo "<tr>";
    echo "<th width=25%>Alias</th>";
    echo "<th width=25%>Times Used</th>";
    echo "<th width=25%>First Used</th>";
    echo "<th width=25%>Last Used</th>";
    echo "</tr>";
    $countRow = 0;
    $class = 1;
while ($row = mysql_fetch_assoc($result)) {
$countRow += 1;
$timesused=$row['num_used'];
$alias=$row['alias'];
$alias=htmlentities($alias);
$firstused=$row['time_add'];
$firstused = date('d M Y H:i:s', $firstused);
$lastused=$row['time_edit'];
$lastused = date('d M Y H:i:s', $lastused);
    echo "<tr align=center>";
    echo "<td class='visible".$class.">$alias</td>";
    echo "<td class='visible".$class.">$timesused</td>";
    echo "<td class='visible".$class.">$firstused</td>";
    echo "<td class='visible".$class.">$lastused</td>";
    echo "</tr>";
    if($countRow == 50){ $class += 1; $countRow = 0; }
}
    echo "</table>";
?>

我现在想写一个函数来解析我的值,这样我就可以这样做:

<ConfigItem Name="ParameterName" Value="1.3" Type="Double"/>

最初我尝试使用其返回类型重载double value = GetItemValue("//ConfigItem[@Name='ParameterName']"); ,但这在C#中是不可能的。我现在尝试使用泛型函数,以便我这样做:

GetItemValue

我试图写的功能是这样的:

double value = GetItemValue<double>("//ConfigItem[@Name='ParameterName']");

不幸的是,这不起作用,我收到以下错误:

public T GetItemValue<T>(string configName)
{
    list = XmlConfig.SelectNodes(configName);

    T returnValue;
    if (T.TryParse(list[0].Attributes["Value"].Value, out returnValue))
        return returnValue;
    else
        throw new InvalidProgramException("Could not parse: " + configName);
}

我不确定问题是什么,但我怀疑,它必须考虑到这样一个事实,即在编译时不清楚所有类型Error CS0119 'T' is a type parameter, which is not valid in the given context 是否都有方法T 。我尝试使用像TryParse这样的约束来解决这个问题,但C#约束不支持ValueTypes。

那么问题是什么,我该如何实现,我想做什么?请注意,对于将来我还需要where T : Int, Double的自定义类型的任何建议。

1 个答案:

答案 0 :(得分:0)

标准类型。

假设您只需要标准的内置基元类型,那么您可以使用Convert或其他内容。

使用自定义类型的正确方法。

但是如果您需要支持自定义类型,则可以使用TypeConverter。这是一种笨重的方式,但可能是最正确的。 (虽然老实说我从来没有完全尝试过它)

简单的自定义解决方案。

如果你不想搞砸TypeConverter,你可以随时使用这样的东西,假设你的自定义类型采用静态Parse(String)方法:

public class Value
{
    private readonly Int32 _value;
    public Value(Int32 value)
    {
        this._value = value;
    }

    public override String ToString()
    {
        return String.Format("Value {0}", this._value);
    }

    public static Value Parse(String str)
    {
        return new Value(Int32.Parse(str));
    }
}


public class Converter
{
    private readonly IDictionary<Type, Func<String, Object>> _parseFunctions;

    public Converter()
    {
        this._parseFunctions = new Dictionary<Type, Func<String, Object>>();
    }

    public T Convert<T>(String str)
    {
        Func<String, Object> parse;
        if (this._parseFunctions.TryGetValue(typeof(T), out parse))
        {
            return (T)parse(str);
        }

        var parseMethodInfo = typeof(T)
            .GetMethod(
                name: "Parse",
                bindingAttr: BindingFlags.Static | BindingFlags.Public,
                binder: null,
                types: new[] { typeof(String) },
                modifiers: null);

        if (parseMethodInfo != null)
        {
            var parameters = new [] { Expression.Parameter(typeof(String)) };
            parse = Expression
                .Lambda<Func<String, Object>>(
                    Expression.Convert(
                        expression: Expression.Call(null, parseMethodInfo, parameters),
                        type: typeof(Object)),
                    parameters: parameters)
                .Compile();
            this._parseFunctions.Add(typeof(T), parse);
            return (T)parse(str);
        }

        return (T)System.Convert.ChangeType(str, typeof(T));
    }
}

public static void Main()
{
    try
    {
        var converter = new Converter();
        Console.WriteLine(converter.Convert<Int32>("123"));
        Console.WriteLine(converter.Convert<Double>("123.32"));
        Console.WriteLine(converter.Convert<Value>("500"));
        Console.WriteLine(converter.Convert<Value>("600"));
    }
    catch (Exception exc)
    {
        Console.WriteLine(exc);
    }
    Console.WriteLine("Press any key...");
    Console.ReadKey(true);         
}