2010-10-07 43 views
6

Tôi đang cố gắng viết một phương pháp chung để tìm giá trị XElement theo kiểu được đánh máy mạnh. Dưới đây là những gì tôi có:Cách truyền sang tham số chung trong 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); 
     } 
    } 
} 

Như bạn có thể nhìn thấy trên đường First attempt của GetElementValue, tôi đang cố gắng để đi từ chuỗi -> đối tượng -> TElementType. Thật không may, điều này không làm việc cho một trường hợp thử nghiệm số nguyên. Khi chạy thử nghiệm sau đây:

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

tôi nhận được ngoại lệ sau khi GetElementValue<int> được gọi là:

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

Tôi sẽ phải xử lý từng trường hợp đúc (hoặc ít nhất là những số) riêng biệt?

Trả lời

11

Bạn cũng có thể thử các chuỗi Convert.ChangeType

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

Điều này phù hợp với tôi. 'ChangeType' trả về một đối tượng vẫn còn, nhưng hàm cast ngầm hiện hoạt động. Ngoài ra, bây giờ tôi kiểm tra 'FormatException' thay vì' InvalidCastException' trong khối 'try/catch'. Câu trả lời ngắn và đơn giản. – Scott

+0

Sau khi điều tra thêm, bạn không thể sử dụng điều này với các loại nullable. Vì vậy, bằng cách sử dụng bài viết này: http://aspalliance.com/852 Tôi đã viết một phương pháp mở rộng để xử lý cả hai loại. – Scott

1

Trong C# bạn không thể truyền đối tượng chuỗi thành Int32. Ví dụ mã này tạo ra lỗi biên dịch:

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

Cố gắng sử dụng Convert class hoặc Int32.ParseInt32.TryParse phương pháp nếu bạn muốn chức năng như vậy.
Và có, bạn nên xử lý tách số, nếu bạn muốn truyền chuỗi thành int.

2

Bạn không thể làm một diễn viên tiềm ẩn hoặc rõ ràng String-Int32, bạn cần sử dụng Int32 's Parse hoặc TryParse phương pháp cho việc này. Có thể bạn có thể tạo một số phương pháp tiện ích tiện lợi, ví dụ:

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 
    } 

Tôi thường sử dụng các phương pháp này thường xuyên.

0

cũng thực hiện IConvertible, vì vậy bạn có thể làm như sau.

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

Bạn thậm chí có thể ném một số phương pháp mở rộng xung quanh để làm cho nó sạch hơn.

3

Từ mã của bạn, thay vì:

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

bạn muốn làm điều này:

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

Thông báo trước đây là TElementType phải thực hiện IConvertible. Tuy nhiên, nếu bạn chỉ nói về các loại nội tại, thì tất cả chúng đều thực hiện điều đó.

Đối với các loại tùy chỉnh của bạn, giả sử bạn muốn chúng ở đây, bạn sẽ phải có chuyển đổi của riêng mình.

Các vấn đề liên quan