Как привести к обычному параметру в C #? - PullRequest
7 голосов
/ 07 октября 2010

Я пытаюсь написать общий метод для извлечения значения XElement строго типизированным способом.Вот что у меня есть:

public static class XElementExtensions
{
    public static XElement GetElement(this XElement xElement, string elementName)
    {
        // Calls xElement.Element(elementName) and returns that xElement (with some validation).
    }

    public static TElementType GetElementValue<TElementType>(this XElement xElement, string elementName)
    {
        XElement element = GetElement(xElement, elementName);
        try
        {
            return (TElementType)((object) element.Value); // First attempt.
        }
        catch (InvalidCastException originalException)
        {
            string exceptionMessage = string.Format("Cannot cast element value '{0}' to type '{1}'.", element.Value,
                typeof(TElementType).Name);
            throw new InvalidCastException(exceptionMessage, originalException);
        }
    }
}

Как вы можете видеть в строке First attempt GetElementValue, я пытаюсь перейти от строки -> объект -> TElementType.К сожалению, это не работает для целочисленного теста.При выполнении следующего теста:

[Test]
public void GetElementValueShouldReturnValueOfIntegerElementAsInteger()
{
    const int expectedValue = 5;
    const string elementName = "intProp";
    var xElement = new XElement("name");
    var integerElement = new XElement(elementName) { Value = expectedValue.ToString() };
    xElement.Add(integerElement);

    int value = XElementExtensions.GetElementValue<int>(xElement, elementName);

    Assert.AreEqual(expectedValue, value, "Expected integer value was not returned from element.");
}

При вызове GetElementValue<int> появляется следующее исключение:

System.InvalidCastException: Невозможно привести значение элемента '5' к типу 'Int32 '.

Должен ли я обрабатывать каждый случай приведения (или хотя бы числовой) отдельно?

Ответы [ 5 ]

11 голосов
/ 07 октября 2010

Вы также можете попробовать Convert.ChangeType

Convert.ChangeType(element.Value, typeof(TElementType))
3 голосов
/ 07 октября 2010

Из вашего кода вместо:

return (TElementType)((object) element.Value);

вы бы сделали это:

return (TElementType) Convert.ChangeType(element.Value, typeof (T));

Единственное предостережение здесь заключается в том, что TElementType должен реализовывать IConvertible.Однако, если вы просто говорите о внутренних типах, они все уже реализуют это.

Для ваших пользовательских типов, если вы хотите, чтобы они были здесь, вам понадобится ваше собственное преобразование.

2 голосов
/ 07 октября 2010

Вы не можете выполнить явное или явное приведение от String до Int32, для этого вам нужно использовать Int32 Parse или TryParse методы.Возможно, вы могли бы создать несколько изящных методов расширения, например:

    using System;
    using System.Diagnostics;
    using System.Globalization;
    using System.Text;

    /// <summary>
    /// Provides extension methods for strings.
    /// </summary>
    public static class StringExtensions
    {
        #region Methods
        /// <summary>
        /// Converts the specified string to a <see cref="Boolean"/>
        /// </summary>
        /// <param name="string">The string to convert.</param>
        /// <returns>The specified string as a <see cref="Boolean"/>.</returns>
        public static bool AsBoolean(this string @string)
        {
            return bool.Parse(@string);
        }

        /// <summary>
        /// Converts the specified string to a <see cref="Boolean"/> using TryParse.
        /// </summary>
        /// <remarks>
        /// If the specified string cannot be parsed, the default value (if valid) or false is returned.
        /// </remarks>
        /// <param name="string">The string to convert.</param>
        /// <param name="default">The default value for if the value cannot be parsed.</param>
        /// <returns>The specified string as a <see cref="DateTime"/>.</returns>
        public static bool AsBooleanNonStrict(this string @string, bool? @default = null)
        {
            bool @bool;
            if ((!string.IsNullOrEmpty(@string)) && bool.TryParse(@string, out @bool))
                return @bool;

            if (@default.HasValue)
                return @default.Value;

            return false;
        }

        /// <summary>
        /// Converts the specified string to a <see cref="DateTime"/>
        /// </summary>
        /// <param name="string">The string to convert.</param>
        /// <returns>The specified string as a <see cref="DateTime"/>.</returns>
        public static DateTime AsDateTime(this string @string)
        {
            return DateTime.Parse(@string);
        }

        /// <summary>
        /// Converts the specified string to a <see cref="DateTime"/> using TryParse.
        /// </summary>
        /// <remarks>
        /// If the specified string cannot be parsed, <see cref="DateTime.MinValue"/> is returned.
        /// </remarks>
        /// <param name="string">The string to convert.</param>
        /// <param name="default">The default value for if the value cannot be parsed.</param>
        /// <returns>The specified string as a <see cref="DateTime"/>.</returns>
        public static DateTime AsDateTimeNonStrict(this string @string, DateTime? @default = null)
        {
            DateTime datetime;
            if ((!string.IsNullOrEmpty(@string)) && DateTime.TryParse(@string, out datetime))
                return datetime;

            if (@default.HasValue)
                return @default.Value;

            return DateTime.MinValue;
        }

        /// <summary>
        /// Converts the specified string to a <see cref="TEnum"/>
        /// </summary>
        /// <param name="string">The string to convert.</param>
        /// <returns>The specified string as a <see cref="TEnum"/>.</returns>
        public static TEnum AsEnum<TEnum>(this string @string) where TEnum : struct
        {
            return (TEnum)Enum.Parse(typeof(TEnum), @string);
        }

        /// <summary>
        /// Converts the specified string to a <see cref="TEnum"/>
        /// </summary>
        /// <param name="string">The string to convert.</param>
        /// <returns>The specified string as a <see cref="TEnum"/>.</returns>
        public static TEnum AsEnumNonStrict<TEnum>(this string @string, TEnum @default) where TEnum : struct
        {
            TEnum @enum;
            if ((!string.IsNullOrEmpty(@string)) && Enum.TryParse(@string, out @enum))
                return @enum;

            return @default;
        }

        /// <summary>
        /// Converts the specified string to a <see cref="Int32"/>
        /// </summary>
        /// <param name="string">The string to convert.</param>
        /// <returns>The specified string as a <see cref="Int32"/>.</returns>
        public static int AsInteger(this string @string)
        {
            return int.Parse(@string);
        }

        /// <summary>
        /// Converts the specified string to a <see cref="Int32"/> using TryParse.
        /// </summary>
        /// <remarks>
        /// If the specified string cannot be parsed, the default value (if valid) or 0 is returned.
        /// </remarks>
        /// <param name="string">The string to convert.</param>
        /// <param name="default">The default value for if the value cannot be parsed.</param>
        /// <returns>The specified string as a <see cref="Int32"/>.</returns>
        public static int AsIntegerNonStrict(this string @string, int? @default = null)
        {
            int @int;
            if ((!string.IsNullOrEmpty(@string)) && int.TryParse(@string, out @int))
                return @int;

            if (@default.HasValue)
                return @default.Value;

            return 0;
        }

        /// <summary>
        /// Converts the specified string to a <see cref="bool"/>
        /// </summary>
        /// <param name="string">The string to convert.</param>
        /// <returns>The specified string as a <see cref="DateTime"/>.</returns>
        public static bool? AsNullableBolean(this string @string)
        {
            bool @bool;
            if ((string.IsNullOrEmpty(@string)) || !bool.TryParse(@string, out @bool))
                return null;

            return @bool;
        }

        /// <summary>
        /// Converts the specified string to a <see cref="DateTime"/>
        /// </summary>
        /// <param name="string">The string to convert.</param>
        /// <returns>The specified string as a <see cref="DateTime"/>.</returns>
        public static DateTime? AsNullableDateTime(this string @string)
        {
            DateTime dateTime;
            if ((string.IsNullOrEmpty(@string)) || !DateTime.TryParse(@string, out dateTime))
                return null;

            return dateTime;
        }

        /// <summary>
        /// Converts the specified string to a <see cref="DateTime"/>
        /// </summary>
        /// <param name="string">The string to convert.</param>
        /// <returns>The specified string as a <see cref="DateTime"/>.</returns>
        public static TEnum? AsNullableEnum<TEnum>(this string @string) where TEnum : struct
        {
            TEnum @enum;
            if ((string.IsNullOrEmpty(@string)) || !Enum.TryParse(@string, out @enum))
                return null;

            return @enum;
        }

        /// <summary>
        /// Converts the specified string to a <see cref="Int32"/>
        /// </summary>
        /// <param name="string">The string to convert.</param>
        /// <returns>The specified string as a <see cref="Int32"/>.</returns>
        public static int? AsNullableInteger(this string @string)
        {
            int @int;
            if ((string.IsNullOrEmpty(@string)) || !int.TryParse(@string, out @int))
                return null;

            return @int;
        }
        #endregion
    }

Я обычно использую их довольно часто.

1 голос
/ 07 октября 2010

В C # вы не можете привести строковый объект к Int32. Например, этот код выдает ошибку компиляции:

    string a = "123.4";
    int x = (int) a;

Попробуйте использовать Преобразовать класс или Int32.Parse и Int32.TryParse , если вам нужна такая функциональность.
И да, вам следует обрабатывать преобразование чисел отдельно, если вы хотите преобразовать строку в int.

0 голосов
/ 07 октября 2010

string также реализует IConvertible, поэтому вы можете сделать следующее.

((IConvertible)mystring).ToInt32(null);

Вы можете даже добавить несколько методов расширения, чтобы сделать его чище.

...