使用输出的通用类型参数

时间:2010-04-29 13:47:21

标签: c# .net parsing polymorphism

我试图使用泛型类型参数创建通用解析器,但我无法掌握100%的概念

    private bool TryParse<T>(XElement element, string attributeName, out T value) where T : struct
    {
        if (element.Attribute(attributeName) != null && !string.IsNullOrEmpty(element.Attribute(attributeName).Value))
        {
            string valueString = element.Attribute(attributeName).Value;
            if (typeof(T) == typeof(int))
            {
                int valueInt;
                if (int.TryParse(valueString, out valueInt))
                {
                    value = valueInt;
                    return true;
                }
            }
            else if (typeof(T) == typeof(bool))
            {
                bool valueBool;
                if (bool.TryParse(valueString, out valueBool))
                {
                    value = valueBool;
                    return true;
                }
            }
            else
            {
                value = valueString;
                return true;
            }
        }

        return false;
    }

正如您可能猜到的,代码无法编译,因为我无法将int | bool | string转换为T(例如,value = valueInt)。感谢您的反馈,我甚至可能无法做到这一点。使用.NET 3.5

8 个答案:

答案 0 :(得分:4)

XElement和XAttribute类都提供a set of explicit conversion operators(强制转换)以方便地将其内容转换为.NET基元类型。

例如,您可以执行以下操作:

XElement elem = // ...

string value1 = (string)elem.Attribute("myString");
int    value2 = (int)elem.Attribute("myInt");
int?   value3 = (int?)elem.Attribute("myOptionalInt");
bool   value4 = (bool)elem.Attribute("myBool");

答案 1 :(得分:2)

不是最好的东西,但是如果你在物体上进行循环,你可以将你的T投射到别的东西,即首先投射到物体然后投射到T,反之亦然。我没有说你是否进入装箱/拆箱的东西,但编译器会接受这个。

答案 2 :(得分:2)

看到你只是写了一个伟大的if / then组合,我认为只要有一堆重载就会好一些:

public static class Parser
{
    private static string TryParseCommon(XElement element, string attributeName)
    {
        if (element.Attribute(attributeName) != null && !string.IsNullOrEmpty(element.Attribute(attributeName).Value))
        {
            return element.Attribute(attributeName).Value;
        }

        return null;
    }

    public static bool TryParse(XElement element, string attributeName, out string value)
    {
        value = TryParseCommon(element, attributeName);
        return true;
    }

    public static bool TryParse(XElement element, string attributeName, out int value)
    {
        return int.TryParse(TryParseCommon(element, attributeName), out value);
    }

    public static bool TryParse(XElement element, string attributeName, out bool value)
    {
        return bool.TryParse(TryParseCommon(element, attributeName), out value);
    }
}

答案 3 :(得分:1)

在使用TypeConverter之前我已经完成了Parse方法。

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

答案 4 :(得分:1)

这可能适合你。

private bool TryParse<T>(XElement element, string attributeName,out T value)
{
    if (element.Attribute(attributeName) != null && !string.IsNullOrEmpty(element.Attribute(attributeName).Value))
    {
        string valueString = element.Attribute(attributeName).Value;
        TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
        try
        {
            value = (T)converter.ConvertFrom(valueString);
            return true;
        }
        catch
        {
            value = default(T);
            return false;
        }
    }
    value = default(T);
    return false;
}

答案 5 :(得分:1)

答案 6 :(得分:1)

问题在于你正试图制作一些非常的泛型。即使您手动循环浏览自己可以解析的每种类型,也不会允许所有类型。

为什么不试试这个呢?首先定义一个描述一般TryParse方法的委托:

public delegate bool TryParser<T>(string text, out T value);

然后重构您的方法,将其中一个作为参数:

// uglified code to fit within horizontal scroll area
public bool TryParse<T>
(XElement element, string attributeName, TryParser<T> tryParser, out T value)
{
    value = default(T);

    if (
        element.Attribute(attributeName) != null &&
        !string.IsNullOrEmpty(element.Attribute(attributeName).Value)
    )
    {
        string valueString = element.Attribute(attributeName).Value;
        return tryParser(valueString, out value);
    }

    return false;
}

现在,为所有标准类型重载这一点非常简单:

public bool TryParseInt(XElement element, string attributeName, out int value)
{
    return TryParse<int>(element, attributeName, int.TryParse, out value);
}

public bool TryParseBool(XElement element, string attributeName, out bool value)
{
    return TryParse<bool>(element, attributeName, bool.TryParse, out value);
}

等等。

这种方法的优点在于它甚至不会限制您使用where T : struct约束,甚至是内置.NET类型。此解析器类的用户可以通过为他/她的自定义类型定义类似TryParse的方法,从XML文档中解析出他/她自己的自定义类型。

答案 7 :(得分:1)

我过去使用的这种方法也可能有所帮助

public static T ChangeTypeTo<T>(this object value)
{
    if (value == null)
        return null;

    Type underlyingType = typeof (T);
    if (underlyingType == null)
        throw new ArgumentNullException("value");

    if (underlyingType.IsGenericType && underlyingType.GetGenericTypeDefinition()
                                            .Equals(typeof (Nullable<>)))
    {
        var converter = new NullableConverter(underlyingType);
        underlyingType = converter.UnderlyingType;
    }

    // Guid convert
    if (underlyingType == typeof (Guid))
    {
        return new Guid(value.ToString());
    }

    // Check for straight conversion or value.ToString conversion
    var objType = value.GetType();

    // If this is false, lets hope value.ToString can convert otherwise exception
    bool objTypeAssignable2typeT = underlyingType.IsAssignableFrom(objType);

    // Do conversion
    return (T) (objTypeAssignable2typeT ? 
              Convert.ChangeType(value, underlyingType)
            : Convert.ChangeType(value.ToString(), underlyingType));
}