2010-10-07 19 views
6

Próbuję napisać ogólną metodę pobierania wartości XElement w sposób mocno napisany. Oto co mam:Jak przesłać do ogólnego parametru w języku C#?

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

Jak widać na linii GetElementValueFirst attempt, staram się iść z łańcucha -> object -> TElementType. Niestety, to nie działa dla przypadku testowego typu integer. Kiedy uruchomiony następujący test:

[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."); 
} 

otrzymuję następujący wyjątek podczas GetElementValue<int> nazywa się:

System.InvalidCastException : Cannot cast element value '5' to type 'Int32'.

będę musiał obsłużyć każdego odlewu sprawę (lub przynajmniej te liczbowe) osobno?

Odpowiedz

11

Można również spróbować ciąg Convert.ChangeType

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

To działa dla mnie. 'ChangeType' zwraca obiekt nadal, ale domyślny rzut działa teraz. Dodatkowo, teraz sprawdzam 'FormatException' zamiast' InvalidCastException' w bloku 'try/catch'. Krótka i prosta odpowiedź. – Scott

+0

Po dalszych badaniach nie można tego użyć z typami zerowymi. Więc używając tego artykułu: http://aspalliance.com/852 Napisałem metodę rozszerzenia do obsługi obu typów. – Scott

1

W języku C# nie można przesyłać obiektu typu string do formatu Int32. Na przykład ten kod generuje błąd kompilacji:

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

spróbuje użyć Convert class lub Int32.Parse i Int32.TryParse metod, jeśli chcesz taką funkcjonalność.
I tak, należy obsłużyć oddzielanie liczbowe osobno, jeśli chcesz przesłać string do int.

2

Nie można zrobić bezpośrednia lub pośrednia odlana z String do Int32, trzeba użyć Int32 „s Parse lub TryParse metody to. Prawdopodobnie możesz utworzyć pewne fajne metody rozszerzania, np .:

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 
    } 

Zwykle używam ich dość często.

0

realizuje również IConvertible, dzięki czemu można wykonać następujące czynności.

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

Można nawet rzucić niektóre metody rozszerzenia wokół niego, aby było czystsze.

3

Od kodzie, zamiast:

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

chcesz to zrobić:

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

Jedyne zastrzeżenie jest to, że TElementType musi wdrożyć IConvertible. Jeśli jednak mówisz tylko o typach wewnętrznych, wszystkie one już to wdrożą.

Dla twoich niestandardowych typów, zakładając, że chciałeś ich tutaj, musiałbyś mieć własną konwersję.

Powiązane problemy