简体   繁体   English

使用输出的通用类型参数

[英]Generic type parameters using out

Im trying to make a universal parser using generic type parameters, but i can't grasp the concept 100% 我试图使用泛型类型参数制作通用解析器,但我无法掌握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;
    }

As you might guess, the code doesn't compile, since i can't convert int|bool|string to T (eg. value = valueInt). 正如您可能猜到的,代码无法编译,因为我无法将int | bool | string转换为T(例如,value = valueInt)。 Thankful for feedback, it might not even be possible to way i'm doing it. 感谢您的反馈,我甚至可能无法做到这一点。 Using .NET 3.5 使用.NET 3.5

The XElement and XAttribute classes both provide a set of explicit conversion operators (casts) to conveniently convert their contents to .NET primitive types. XElement和XAttribute类都提供了一组显式转换运算符 (强制转换),以方便地将其内容转换为.NET基元类型。

For example, you can simply do: 例如,您可以简单地执行以下操作:

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");

Not the nicest of things but you can cast your T to something else if you do the cycle over object, ie first cast to object then to T, or vice versa. 不是最好的东西,但是如果你在对象上进行循环,你可以将你的T转换为其他东西,即首先转换为object然后转换为T,反之亦然。 I am not saying anything about whether you get into boxing / unboxing stuff, but the compiler will accept this. 我没有说你是否进入拳击/拆箱的东西,但编译器会接受这个。

Seeing as you're only writing a great big if/then combo, I think you'd be better off simply with a bunch of overloads: 看到你只是写了一个伟大的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);
    }
}

I've done Parse methods before using a TypeConverter . 在使用TypeConverter之前我已经完成了Parse方法。

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

This might work for you. 这可能对你有用。

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;
}

The problem is that you're trying to make something generic that really isn't. 问题是你正在尝试制作一些通用的东西。 Even if you manually cycle through every type that you yourself can parse, that's not going to allow for all types. 即使您手动循环浏览自己可以解析的每种类型,也不会允许所有类型。

Why don't you try this instead? 你为什么不尝试这个呢? First define a delegate that describes a general TryParse method: 首先定义一个描述一般TryParse方法的委托:

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

Then restructure your method to take one of these as a parameter: 然后重构您的方法,将其中一个作为参数:

// 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;
}

Now, overloading this for all the standard types is quite trivial: 现在,为所有标准类型重载这一点非常简单:

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);
}

And so on. 等等。

What's nice about this approach is that it doesn't even restrict you to using a where T : struct constraint, or even to the built-in .NET types. 这种方法的好处在于它甚至不会限制你使用where T : struct约束,甚至是内置的.NET类型。 A user of this parser class could parse out his/her own custom types from an XML document simply by defining a TryParse -like method for his/her custom types. 该解析器类的用户可以简单地通过为他/她的自定义类型定义类似TryParse的方法,从XML文档中解析出他/她自己的自定义类型。

This method I've used in the past might help out some too 我过去使用的这种方法也可能有所帮助

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));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM