Универсальный TryParse

Я протестировал его так, и он сработал:

SET /P Var= | Cmd

Путем передачи команды в переменную приглашение вставляет результат команды «Cmd» в переменную «Var ".

Обновление:

Это не работает, мой плохой, сценарий, который я сделал, был следующим:

SET /P Var= | dir /b *.txt
echo %Var%

Это на самом деле показывало, скажем, «test.txt», но на самом деле он показывал результат команды «dir /b *.txt», а не echo %var%. Я запутался, так как оба выхода были одинаковыми.

190
задан Piers Myers 2 June 2010 в 13:05
поделиться

10 ответов

Вы должны использовать класс TypeDescriptor :

public static T Convert<T>(this string input)
{
    try
    {
        var converter = TypeDescriptor.GetConverter(typeof(T));
        if(converter != null)
        {
            // Cast ConvertFromString(string text) : object to (T)
            return (T)converter.ConvertFromString(input);
        }
        return default(T);
    }
    catch (NotSupportedException)
    {
        return default(T);
    }
}
174
ответ дан 23 November 2019 в 05:36
поделиться

Используя информацию выше, это то, что я разработал. Это позволит преобразовать объект напрямую, в противном случае он преобразует объект в строку и вызовет метод TryParse для нужного типа объекта.

Я кэширую методы в словаре, так как каждый встречается, чтобы уменьшить нагрузку при извлечении метода.

Можно проверить, можно ли напрямую преобразовать объект в целевой тип, что еще больше уменьшит часть преобразования строк. Но я оставлю это пока.

    /// <summary>
    /// Used to store TryParse converter methods
    /// </summary>
    private static readonly Dictionary<Type, MethodInfo> TypeConverters = new Dictionary<Type, MethodInfo>();

    /// <summary>
    /// Attempt to parse the input object to the output type
    /// </summary>
    /// <typeparam name="T">output type</typeparam>
    /// <param name="obj">input object</param>
    /// <param name="result">output result on success, default(T) on failure</param>
    /// <returns>Success</returns>
    public static bool TryParse<T>([CanBeNull] object obj, out T result)
    {
        result = default(T);

        try
        {
            switch (obj)
            {
                // don't waste time on null objects
                case null: return false;

                // if the object is already of type T, just return the value
                case T val:
                    result = val;
                    return true;
            }

            // convert the object into type T via string conversion
            var input = ((obj as string) ?? obj.ToString()).Trim();
            if (string.IsNullOrEmpty(input)) return false;

            var type = typeof (T);
            Debug.WriteLine($"Info: {nameof(TryParse)}<{type.Name}>({obj.GetType().Name}=\"{input}\")");

            if (! TypeConverters.TryGetValue(type, out var method))
            {
                // get the TryParse method for this type
                method = type.GetMethod("TryParse",
                    new[]
                    {
                        typeof (string),
                        Type.GetType($"{type.FullName}&")
                    });

                if (method is null)
                    Debug.WriteLine($"FAILED: Cannot get method for {type.Name}.TryParse()");

                // store it so we don't have to do this again
                TypeConverters.Add(type, method);
            }

            // have to keep a reference to parameters if you want to get the returned ref value
            var parameters = new object[] {input, null};
            if ((bool?) method?.Invoke(null, parameters) == true)
            {
                result = (T) parameters[1];
                return true;
            }                
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex);
        }

        return false;
    }
0
ответ дан 23 November 2019 в 05:36
поделиться

T.TryParse..., почему?

я не вижу преимущества в наличии такого дженерика TryParse функция. Существует слишком много различных стратегий парсинга и преобразования данных между различными типами с возможным конфликтующим поведением. Как эта функция могла знать который стратегия выбрать контекстно-свободным способом?

  • классы со специализированными функциями TryParse можно было назвать
  • , классы со специализированными функциями Синтаксического анализа могли быть перенесены с выгодой попытки и результатом bool
  • классы с перегрузками оператора, как Вы позволите им обработать парсинг?
  • дескрипторы типа являются встроенным использованием Convert.ChangeType. Этот API настраиваем во времени выполнения. Ваша функция требует поведения по умолчанию или допускает настройку?
  • необходимо ли позволить какой-либо платформе отображения пытаться проанализировать для Вас?
  • , как Вы обработали бы конфликты в вышеупомянутом?
0
ответ дан 23 November 2019 в 05:36
поделиться

Я поместил набор идей здесь вместе и закончил с очень коротким решением.

Это - дополнительный метод на строке

enter code here

, я сделал его с тем же следом как методы TryParse на числовых типах

    /// <summary>
    /// string.TryParse()
    /// 
    /// This generic extension method will take a string
    ///     make sure it is not null or empty
    ///     make sure it represents some type of number e.g. "123" not "abc"
    ///     It then calls the appropriate converter for the type of T
    /// </summary>
    /// <typeparam name="T">The type of the desired retrunValue e.g. int, float, byte, decimal...</typeparam>
    /// <param name="targetText">The text to be converted</param>
    /// <param name="returnValue">a populated value of the type T or the default(T) value which is likely to be 0</param>
    /// <returns>true if the string was successfully parsed and converted otherwise false</returns>
    /// <example>
    /// float testValue = 0;
    ///  if ( "1234".TryParse<float>( out testValue ) )
    ///  {
    ///      doSomethingGood();
    ///  }
    ///  else
    ///  {
    ///      handleTheBadness();
    ///  }
    /// </example>
    public static bool TryParse<T>(this string targetText, out T returnValue )
    {
        bool returnStatus = false;

        returnValue = default(T);

        //
        // make sure the string is not null or empty and likely a number...
        // call whatever you like here or just leave it out - I would
        // at least make sure the string was not null or empty  
        //
        if ( ValidatedInputAnyWayYouLike(targetText) )
        {

            //
            // try to catch anything that blows up in the conversion process...
            //
            try
            {
                var type = typeof(T);
                var converter = TypeDescriptor.GetConverter(type);

                if (converter != null && converter.IsValid(targetText))
                {
                    returnValue = (T)converter.ConvertFromString(targetText);
                    returnStatus = true;
                }

            }
            catch
            {
                // just swallow the exception and return the default values for failure
            }

        }

        return (returnStatus);

    }

'' '

0
ответ дан 23 November 2019 в 05:36
поделиться

Как вы сказали, TryParse не является частью интерфейса. Он также не является членом какого-либо базового класса, поскольку на самом деле статические и статические функции не могут быть виртуальными . Итак, компилятор не может гарантировать, что T действительно имеет член с именем TryParse , поэтому это не сработает.

Как сказал @Mark, вы можете создать свой собственный интерфейс и использовать пользовательские типы, но вам не повезло со встроенными типами.

1
ответ дан 23 November 2019 в 05:36
поделиться

Это вопрос «общих ограничений». Поскольку у вас нет определенного интерфейса, вы застряли, если не последуете предложениям предыдущего ответа.

Для документации по этому поводу проверьте следующую ссылку:

http://msdn.microsoft.com/en-us/library/ms379564 (VS.80) .aspx

Здесь показано, как использовать эти ограничения и должны дать вам еще несколько подсказок.

0
ответ дан 23 November 2019 в 05:36
поделиться

Когда я хотел сделать почти то же самое, мне приходилось реализовывать это на собственном горьком опыте, учитывая размышления. Учитывая T , подумайте о typeof (T) и найдите метод TryParse или Parse , вызывая его, если вы его нашли. .

2
ответ дан 23 November 2019 в 05:36
поделиться

Как насчет этого?

http://madskristensen.net/post/Universal-data-type-checker.aspx ( Архив )

/// <summary> 
/// Checks the specified value to see if it can be 
/// converted into the specified type. 
/// <remarks> 
/// The method supports all the primitive types of the CLR 
/// such as int, boolean, double, guid etc. as well as other 
/// simple types like Color and Unit and custom enum types. 
/// </remarks> 
/// </summary> 
/// <param name="value">The value to check.</param> 
/// <param name="type">The type that the value will be checked against.</param> 
/// <returns>True if the value can convert to the given type, otherwise false. </returns> 
public static bool CanConvert(string value, Type type) 
{ 
    if (string.IsNullOrEmpty(value) || type == null) return false;
    System.ComponentModel.TypeConverter conv = System.ComponentModel.TypeDescriptor.GetConverter(type);
    if (conv.CanConvertFrom(typeof(string)))
    { 
        try 
        {
            conv.ConvertFrom(value); 
            return true;
        } 
        catch 
        {
        } 
     } 
     return false;
  }

Это может быть легко преобразован в общий метод.

 public static bool Is<T>(this string value)
 {
    if (string.IsNullOrEmpty(value)) return false;
    var conv = System.ComponentModel.TypeDescriptor.GetConverter(typeof(T));

    if (conv.CanConvertFrom(typeof(string)))
    { 
        try 
        {
            conv.ConvertFrom(value); 
            return true;
        } 
        catch 
        {
        } 
     } 
     return false;
}
5
ответ дан 23 November 2019 в 05:36
поделиться

Вы не можете сделать это для общих типов.

Что вы можете сделать, так это создать интерфейс ITryParsable и использовать его для пользовательских типов, которые реализуют этот интерфейс.

Однако я предполагаю, что вы собираетесь использовать его для базовых типов, таких как int и DateTime. Вы не можете изменить эти типы для реализации новых интерфейсов.

4
ответ дан 23 November 2019 в 05:36
поделиться

Если вы настроены на использование TryParse, вы можете использовать отражение и сделать это следующим образом:

public static bool Is<T>(this string input)
{
    var type = typeof (T);
    var temp = default(T);
    var method = type.GetMethod(
        "TryParse",
        new[]
            {
                typeof (string),
                Type.GetType(string.Format("{0}&", type.FullName))
            });
    return (bool) method.Invoke(null, new object[] {input, temp});
}
14
ответ дан 23 November 2019 в 05:36
поделиться
Другие вопросы по тегам:

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