Универсальные параметры типа, использующие

Я пытаюсь сделать универсальный синтаксический анализатор с помощью универсальных параметров типа, но я не могу схватить понятие 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 (например, оценить = valueInt). Благодарный за обратную связь, это даже не могло бы быть возможно к способу, которым я делаю его. Используя.NET 3.5

5
задан Mikael Gidmark 29 April 2010 в 13:47
поделиться

8 ответов

Видя, что вы пишете только отличную большую комбинацию 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);
    }
}
2
ответ дан 18 December 2019 в 14:43
поделиться

Я выполнил методы анализа перед использованием TypeConverter .

TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
try
{
    return (T)converter.ConvertFrom(value);
}
1
ответ дан 18 December 2019 в 14:43
поделиться

Этот метод, который я использовал в прошлом, тоже может помочь некоторым

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));
}
1
ответ дан 18 December 2019 в 14:43
поделиться

Классы XElement и XAttribute предоставляют набор явных операторов преобразования (приведение ) для удобного преобразования их содержимого в примитивные типы .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");
4
ответ дан 18 December 2019 в 14:43
поделиться

Не самая приятная вещь, но вы можете привести ваш T к чему-то другому, если вы сделаете цикл над объектом, т.е. сначала привести к объекту, затем к T, или наоборот. Я ничего не говорю о том, будете ли вы заниматься boxing / unboxing вещами, но компилятор примет это.

2
ответ дан 18 December 2019 в 14:43
поделиться

Проблема в том, что вы пытаетесь сделать что-то общее , что на самом деле не так. Даже если вы вручную перебираете каждый тип, который вы можете проанализировать самостоятельно, это не позволит использовать все типы.

Почему бы вам не попробовать это вместо этого? Сначала определите делегат, который описывает общий метод 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. Пользователь этого класса синтаксического анализатора мог разбирать свои собственные настраиваемые типы из XML-документа, просто определяя TryParse -подобный метод для своих настраиваемых типов.

1
ответ дан 18 December 2019 в 14:43
поделиться

Это может сработать для вас.

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;
}
1
ответ дан 18 December 2019 в 14:43
поделиться
1
ответ дан 18 December 2019 в 14:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: