2009-04-27 19 views
45

は、私は現在のタイプの間の変換を行うために、この便利な変換拡張メソッドを使用します。Nullable <T>に汎用変換を行うにはどうすればよいですか?

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

しかし、それはNULL可能に有効な値を変換する好きではない、例えば、これは失敗:明らか

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

(?int型)、1は簡単に変換し、それがエラーを取得している:

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

これは明らかに簡略化した例で、実際に私たちよそのような文字列型からの変換を行うには、それをINGの:

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

Convert.ChangeTypeがNULL可能が気に入らない場合は、誰もがいずれかの素晴らしいアイデアを持っていますか?

+0

私の質問を参照してください:http://stackoverflow.com/questions/773078/c-convert-string-to-nullable-type-in​​t-double-etc –

答えて

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

ありがとう、ルーク!これは完璧です。 t.GetGenericTypeDefinition()== typeof(Nullable <>))とNullable.GetUnderlyingType(t)は、ここで本当に助けになりました。これは良いことです。再度、感謝します。 – TheSoftwareJedi

+1

必要に応じて、(obj == null) を変更すると便利です。if(obj == null || objがString && obj.ToString()== "") –

+0

T objがnullの場合、 'return default(T)'は単に 'return null'と常に同じではありませんか? – goodeye

2

Nullableのインスタンスでは、(int?)1のような簡単なキャストよりも可読性、パフォーマンス、メンテナンスのどちらの方が優れていますか?

それ以外に、おそらく別の拡張方法ですか?

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

編集

あなたの編集を確認した後、なぜ私はそのコード行であなたのTo<T>関数の代用として機能していない提供される汎用機能のでしょうか?任意のタイプのNullableへの変換を許可することはできません(その理由は、ChangeTypeは機能しません)。そのジェネリックは値タイプのみを受け入れるためです。あなたは、私が提供したような関数を使用するか、値型を受け入れ、Nullable<T>の特別なケースを追加するだけで、To<T>のあなたの署名を変更する必要があります。

+0

はへの道がありますこれを私の既存のメソッドにロールオーバーし、nullableジェネリックを検出して適切に処理させますか? – TheSoftwareJedi

+0

これは、typeof(T).IsGeneric && typeof(T).GetGenericTypeDefinition()。Name.StartsWith( "Nullable"))は、型がNULL可能かどうかを示します。特殊ケースを適用することができますが、が非構造型を受け入れる場合には、それが動作するかどうかはわかりません。 ToNullable を使用するように変更するだけの問題は何でしょうか? –

1

これは、(私はSOに私の答えを得た)私が現在使用している方法であり、それは文字列からNULL値可能型に変換します

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

しかし、変換が失敗した場合、それは例外がスローされます期待どおりにnullを返さない。

+0

良い答え、完璧な進歩はありますが、私は1にしか訂正できません。ルークはヌルチェックをします。乾杯! – TheSoftwareJedi

2

ルークのソリューションは、私にとっては良かった(と明らかに彼のアップ票を得た)が、私はいないタイプから文字列から始めたので、私は私のためにこのよう

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

それを簡素化... 思考?

3

私はそれは、LINQの拡張メソッドSingleSingleOrDefaultFirstFirstOrDefaultのように動作し、この

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

になってしまってきました。

つまり、To<T>()は変換を試みて失敗をスローしますが、ToOrDefault<T>()は変換を試みて、失敗するとdefault(T)を返します。

0

は@LukeHコードを拡張:

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

あなたの答えにいくつかの説明を加えてください。 –

+0

リテラルがnullの場合は、DefaultValueを返します。 elseリテラルをT型に変換します。 –

0

この方法は、何が必要ありませんし、それをやっている間、それは良さそうに見えます。

/// <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