2009-10-31 34 views
12

Mã lấy từ herePhương pháp mở rộng TryParse chung

Tôi muốn nghe một số ý kiến ​​chuyên gia về phương pháp mở rộng này. Tôi có kế hoạch sử dụng nó, nhưng muốn nghe về bất kỳ vấn đề đã biết tôi có thể phải đối mặt.

Tôi có sử dụng tốt hơn trên các kiểu nguyên thủy TryParse phương pháp không?

public static T? TryParse<T>(this object obj) where T : struct 
     { 
      if (obj == null) return null; 

      T? result = null; 
      TypeConverter converter = TypeDescriptor.GetConverter(typeof(T)); 
      if (converter != null) 
      { 
       try 
       { 
        string str = obj.ToString(); 
        result = (T)converter.ConvertFromString(str); 
       } 
       catch (Exception ex) 
       { 
        throw ex; 
       } 
      } 

      return result; 
     } 
+5

Như câu trả lời đã nói, đừng 'ném ex'. Bạn * hiếm khi *, nếu bao giờ, muốn làm điều đó. Chỉ cần 'ném'. –

+4

Nó cũng đánh bại điểm của một 'Thử nghiệm 'nếu bạn ném ngoại lệ ... –

Trả lời

1

Nó sử dụng sự phản chiếu và do đó có thể chậm, nếu hiệu suất là một vấn đề.

3

Generics hữu ích nhất khi bạn muốn thay đổi hợp đồng công khai của một phương thức hoặc lớp học và nội bộ của phương thức hoặc lớp học không thực sự quan tâm (hoặc quan tâm nhiều) về loại thay đổi.

Một số ví dụ:

List<T> là một bộ sưu tập, bạn có thể đặt mọi thứ vào, và trong nội bộ lớp không quan tâm (nhiều) về loại đó là.

T System.Linq.Enumerable.First<T>(IEnumerable<T> source) trả về phần tử đầu tiên trong số các phần tử. Phương pháp này không cần phải biết nội bộ loại đó là để có được công việc làm.

Ngược lại, một phương pháp phân tích cú pháp phải thay đổi hành vi của nó dựa trên loại kết quả. Trong phương thức được cung cấp, có Chiến lược đẩy hành vi ra các phương pháp khác, nhưng có chi phí thời gian chạy cho lựa chọn đó.

Cách khác là để cho người gọi (người phải biết Loại hoặc họ không thể gọi phương thức chung chung với nó), chọn công cụ chuyển đổi. Lựa chọn này có thể được thực hiện tại thời gian thiết kế hoặc thời gian biên dịch và do đó chịu 0 chi phí thời gian chạy.

Ghi chú bên: Vui lòng không sử dụng để ném lại mọi thứ thành ngữ. Tất cả những gì bạn làm là đặt lại ngăn xếp cuộc gọi và bạn không bao giờ muốn làm điều đó.

catch (Exception ex) 
{ 
    throw ex; 
} 
+0

1 động lực để sử dụng phương pháp chung này là giảm mã khách hàng gọi so với sử dụng phân tích cú pháp nguyên thủy. Bạn đúng rằng các máy khách biết các kiểu thời gian chạy nhưng chúng cũng phải xử lý các ngoại lệ. Ngoài ra, u có thể liên kết tôi trên nhiều thông tin hơn resetiing stack trace? Cảm ơn –

+0

Liên kết khôi phục http://msdn.microsoft.com/en-us/library/ms182363(VS.80).aspx –

+0

Và, bạn có thể yêu cầu khách hàng chuyển cho bạn trình phân tích cú pháp (dưới dạng Func nếu không có gì khác) , thay vì loại - điều đó sẽ tránh được sự phản chiếu. –

24

Các mô hình TryParse là tốt nhất theo mô hình tiêu chuẩn, cho phép sử dụng với phi cấu trúc, quá:

public static bool TryParse<T>(string s, out T value) { 
    TypeConverter converter = TypeDescriptor.GetConverter(typeof(T)); 
    try { 
     value = (T) converter.ConvertFromString(s); 
     return true; 
    } catch { 
     value = default(T); 
     return false; 
    } 
} 

Note Tôi đã chấp nhận một string đây, bởi vì đó là những gì tôi phổ biến nhất có nghĩa là TryParse; nếu không, Convert.ChangeType có thể phù hợp hơn.

tôi thấy không có lý do cho điều này là một phương pháp mở rộng (theo this trong ví dụ của câu hỏi), và chắc chắn nó là không lưu ý đến ô nhiễm object với quá nhiều phương pháp khuyến nông.

4

Các tiện ích mở rộng bên dưới có thể hữu ích cho bạn. Họ làm việc trên bất kỳ loại mà có một Parse hoặc phương pháp TryParse ...

Họ đến từ thư viện mở rộng của tôi ở đây: http://www.codeproject.com/KB/dotnet/MBGExtensionsLibrary.aspx

Mặc dù dự án đó có lẽ là một chút out-of-date ... Tôi sẽ phải cập nhật nó như một số điểm :-D

Hy vọng điều này sẽ hữu ích!

public static class StringExtensions 
    { 
     public static TOut ParseOrDefault<TOut>(this string input) 
     { 
      return input.ParseOrDefault(default(TOut)); 
     } 
     public static TOut ParseOrDefault<TOut>(this string input, TOut defaultValue) 
     { 
      Type type = typeof(TOut); 
      MethodInfo parseMethod = type.GetMethod("Parse", new Type[] { typeof(string) }); 

      if (parseMethod != null) 
      { 
       var value = parseMethod.Invoke(null, new string[] { input }); 
       return (value is TOut ? (TOut)value : defaultValue); 
      } 
      else { return defaultValue; } 
     } 
     public static bool TryParseOrDefault<TOut>(this string input, out TOut output) 
     { 
      return input.TryParseOrDefault(out output, default(TOut)); 
     } 
     public static bool TryParseOrDefault<TOut>(this string input, out TOut output, TOut defaultValue) 
     { 
      output = defaultValue; 

      Type type = typeof(TOut); 
      MethodInfo parseMethod = type.GetMethod(
       "TryParse", 
       new Type[] { typeof(string), typeof(TOut).MakeByRefType() }); 

      if (parseMethod != null) 
      { 
       object[] parameters = new object[] { input, output }; 
       var value = parseMethod.Invoke(null, parameters); 

       if (value is bool) 
       { 
        bool successful = (bool)value; 
        if (successful) 
        { 
         output = (TOut)parameters[1]; 
         return true; 
        } 
       } 
      } 
      return false; 
     } 
    } 
+0

Rất tiếc ... Tôi không thấy bài đăng cũ bao nhiêu tuổi! LOL. Xin lỗi vì điều đó. – Matt

+1

Đừng! Đó chỉ là những gì tôi đang tìm kiếm. Cảm ơn! – Yandros

3

Đối với mã đơn giản hơn, bạn có thể làm điều này:

T value = (T)Convert.ChangeType(value, typeof(T)); 

tín dụng đối với Thomas Levesque tại https://stackoverflow.com/a/1465930/24315.

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