2009-04-27 31 views
45

Tôi hiện đang sử dụng phương pháp khuyến nông chuyển đổi hữu ích này để làm chuyển đổi giữa các loại:Làm thế nào tôi có thể sửa lỗi này để thực hiện chuyển đổi chung thành Nullable <T>?

public static T To<T>(this IConvertible obj) 
    { 
     return (T)Convert.ChangeType(obj, typeof(T)); 
    } 

Tuy nhiên, nó không giống như chuyển đổi các giá trị hợp lệ để Nullable, ví dụ, điều này không:

"1".To<int?>(); 

Rõ ràng , 1 có thể dễ dàng chuyển đổi thành một (int?), Nhưng nó bị lỗi:

Invalid cast from 'System.String' to 'System.Nullable`1[[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'. 

Đây là một ví dụ đơn giản rõ ràng, thực tế tôi là chúng tôi để thực hiện chuyển đổi từ các loại chuỗi như vậy:

packageDb.Quantity = package.package.ElementDeep(Namespace + "PackageQuantity", Namespace + "ActualQuantity", Namespace + "Quantity").ValueOrNull().To<int?>(); 

Nếu Convert.ChangeType không thích Nullable, bất kỳ ai có ý tưởng tuyệt vời?

+0

Xem câu hỏi của tôi: http://stackoverflow.com/questions/773078/c-convert-string-to-nullable-type-int-double-etc –

Trả lời

94
public static T To<T>(this IConvertible obj) 
{ 
    Type t = typeof(T); 
    Type u = Nullable.GetUnderlyingType(t); 

    if (u != null) 
    { 
     return (obj == null) ? default(T) : (T)Convert.ChangeType(obj, u); 
    } 
    else 
    { 
     return (T)Convert.ChangeType(obj, t); 
    } 
} 
+0

Cảm ơn Luke! Đây là hoàn hảo. Đó là t.GetGenericTypeDefinition() == typeof (Nullable <>)) và Nullable.GetUnderlyingType (t) thực sự đã giúp tôi ở đây. Đây là thứ tốt. Cảm ơn một lần nữa. – TheSoftwareJedi

+1

Tùy thuộc vào nhu cầu của bạn để thay đổi nếu (obj == null) ĐỂ if (obj == null || obj là String && obj.ToString() == "") –

+0

Làm đơn giản hóa/làm rõ, nếu T là nullable, và obj là null, không phải là 'return default (T)' luôn luôn giống như 'return null'? – goodeye

2

Có thể tôi đang thiếu điểm, nhưng trong trường hợp của Nullable, phương pháp của bạn cung cấp khả năng đọc, hiệu suất hoặc bảo trì như thế nào trên dàn diễn viên đơn giản, chẳng hạn như (int?)1?

Ngoài ra, có lẽ một phương pháp mở rộng khác?

public static T? ToNullable<T>(this T obj) where T:struct 
{ 
    return (T?)obj; 
} 

Sửa

Sau khi xem xét chỉnh sửa của bạn, tại sao một hàm tổng quát mà tôi với điều kiện không làm việc như là một thay thế cho chức năng To<T> của bạn ở chỗ dòng mã? Bạn không thể cho phép chuyển đổi thành Nullable cho bất kỳ loại nào (đó là lý do tại sao ChangeType không hoạt động) vì loại chung đó chỉ chấp nhận các loại giá trị. Bạn sẽ phải sử dụng một chức năng giống như chức năng tôi đã cung cấp hoặc thay đổi chữ ký của mình là To<T> để chỉ chấp nhận các loại giá trị và thêm trường hợp đặc biệt cho Nullable<T>.

+0

Có cách nào để cuộn nó vào phương thức hiện có của tôi, và để nó phát hiện ra giá trị nullable chung, và xử lý một cách thích hợp? – TheSoftwareJedi

+0

Vâng, bạn có thể nói điều này ... if (typeof (T) .IsGeneric && typeof (T) .GetGenericTypeDefinition(). Name.StartsWith ("Nullable")) sẽ cho bạn biết nếu loại đó là nullable. Sau đó bạn có thể áp dụng trường hợp đặc biệt, nhưng tôi không chắc chắn rằng có thể làm việc khi Để chấp nhận các loại không cấu trúc. Điều gì sẽ là vấn đề chỉ thay đổi để sử dụng ToNullable khi đó là những gì bạn muốn? –

1

Đây là phương pháp mà tôi hiện đang sử dụng (tôi có câu trả lời của tôi trên SO), nó chuyển đổi từ xâu thành kiểu nullable:

public static Nullable<T> ConvertToNullable<T>(this string s) where T : struct 
    { 
     if (!string.IsNullOrEmpty(s.Trim())) 
     { 
      TypeConverter conv = TypeDescriptor.GetConverter(typeof(Nullable<>).MakeGenericType(typeof(T))); 
      return (Nullable<T>)conv.ConvertFrom(s); 
     } 
     return null; 
    } 
4
public static T To<T>(this IConvertible obj) 
{ 
    Type t = typeof(T); 
    if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)) 
     t = t.GetGenericArguments()[0]; 

    return (T)Convert.ChangeType(obj, t); 
} 

Nhưng nếu việc chuyển đổi thất bại, nó sẽ ném một ngoại lệ , không trả về giá trị rỗng như mong đợi.

+0

câu trả lời hay, hoàn toàn đúng hướng, nhưng tôi chỉ có thể trao giải chính xác cho 1, và Luke thực hiện kiểm tra không. Chúc mừng! – TheSoftwareJedi

2

giải pháp Luke là tốt cho tôi (và rõ ràng đã bỏ phiếu của mình lên) nhưng tôi đơn giản hóa nó cho tôi theo cách này

private static Type ResolveType(String typeName) 
    { 
     Type t = Type.GetType(typeName); 
     if (t == null) 
      return null; 

     Type u = Nullable.GetUnderlyingType(t); 

     if (u != null) { 
      t = u; 
     } 
     return t; 
    } 

vì tôi bắt đầu từ một chuỗi chứ không phải từ một loại ... suy nghĩ?

3

tôi đã kết thúc với điều này

private static T To<T>(this Object @object, Boolean returnDefaultOnException) 
{ 
    Type type = typeof(T); 
    Type underlyingTypeOfNullable = Nullable.GetUnderlyingType(type); 
    try 
    { 
     return (T) Convert.ChangeType(@object, underlyingTypeOfNullable ?? type); 
    } 
    catch (Exception exception) 
    { 
     if (returnDefaultOnException) 
      return default(T); 
     String typeName = type.Name; 
     if (underlyingTypeOfNullable != null) 
      typeName += " of " + underlyingTypeOfNullable.Name; 
     throw new InvalidCastException("Object can't be cast to " + typeName, exception); 

    } 
} 
public static T To<T>(this Object @object) { return @object.To<T>(returnDefaultOnException: false); } 
public static T ToOrDefault<T>(this Object @object) { return @object.To<T>(returnDefaultOnException: true); } 

Nó hoạt động như các phương pháp khuyến nông LINQ SingleSingleOrDefaultFirstFirstOrDefault.

Tóm lại, To<T>() cố gắng chuyển đổi và ném về thất bại trong khi ToOrDefault<T>() cố gắng chuyển đổi và trả về default(T) về lỗi.

0

mở rộng @LukeH mã:

public static T GetValue<T>(string Literal, T DefaultValue) 
    { 
     if (Literal == null || Literal == "" || Literal == string.Empty) return DefaultValue; 
     IConvertible obj = Literal; 
     Type t = typeof(T); 
     Type u = Nullable.GetUnderlyingType(t); 

     if (u != null) 
     { 
      return (obj == null) ? DefaultValue : (T)Convert.ChangeType(obj, u); 
     } 
     else 
     { 
      return (T)Convert.ChangeType(obj, t); 
     } 
    } 
+0

Vui lòng thêm một số lời giải thích cho câu trả lời của bạn. –

+0

nếu Literal của bạn là null, trả về DefaultValue. chuyển đổi Literal to T Type. –

0

Phương pháp này không những gì bạn cần, và nó có vẻ tốt đẹp khi làm việc đó.

/// <summary> 
    /// <para>More convenient than using T.TryParse(string, out T). 
    /// Works with primitive types, structs, and enums. 
    /// Tries to parse the string to an instance of the type specified. 
    /// If the input cannot be parsed, null will be returned. 
    /// </para> 
    /// <para> 
    /// If the value of the caller is null, null will be returned. 
    /// So if you have "string s = null;" and then you try "s.ToNullable...", 
    /// null will be returned. No null exception will be thrown. 
    /// </para> 
    /// <author>Contributed by Taylor Love (Pangamma)</author> 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    /// <param name="p_self"></param> 
    /// <returns></returns> 
    public static T? ToNullable<T>(this string p_self) where T : struct 
    { 
     if (!string.IsNullOrEmpty(p_self)) 
     { 
      var converter = System.ComponentModel.TypeDescriptor.GetConverter(typeof(T)); 
      if (converter.IsValid(p_self)) return (T)converter.ConvertFromString(p_self); 
      if (typeof(T).IsEnum) { T t; if (Enum.TryParse<T>(p_self, out t)) return t;} 
     } 

     return null; 
    } 

https://github.com/Pangamma/PangammaUtilities-CSharp/tree/master/src/StringExtensions

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