如何在C#中将类型转换为泛型参数?

8

我正在尝试编写一种通用方法,以强类型方式获取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);
        }
    }
}

正如您在GetElementValueFirst attempt行中所看到的,我试图从字符串 -> 对象 -> 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

你还可以尝试使用Convert.ChangeType

Convert.ChangeType(element.Value, typeof(TElementType))

这对我有效。ChangeType仍然返回一个对象,但隐式转换现在起作用了。此外,我现在在try/catch块中检查FormatException而不是InvalidCastException。简短明了的回答。 - Doctor Blue
经过进一步调查,您不能将其与可空类型一起使用。因此,使用本文:http://aspalliance.com/852 我编写了一个扩展方法来处理这两种类型。 - Doctor Blue

3

从你的代码来看,不是:

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

你需要这样做:

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

唯一的注意点是TElementType必须实现IConvertible。不过,如果你只是在谈论内置类型,它们都已经实现了这个接口。
对于自定义类型,假设你想要将它们放在这里,你需要有自己的转换方法。

2

你不能将String隐式或显式转换为Int32,你需要使用Int32ParseTryParse方法来完成。你可以创建一些巧妙的扩展方法,例如:

    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
在C#中,您无法将字符串对象转换为Int32。例如,此代码会产生编译错误:
    string a = "123.4";
    int x = (int) a;

尝试使用Convert类Int32.ParseInt32.TryParse方法,如果您想要这样的功能。
是的,如果您想将字符串转换为整数,应该单独处理数字转换。

0

字符串也实现了IConvertible接口,因此您可以执行以下操作。

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

你甚至可以使用一些扩展方法来使代码更加简洁。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接