2009-05-21 8 views
3

反射を使用して文字列からNullableに変換するにはどうすればよいですか?Reflectを使用して文字列からNullableに変換する<T>

ほとんどすべての値が指定されたほとんどすべての値型に変換する次のコードがあります。 IsAssignableFromなどを使用するには、このコードの上にかなりのコードがありますので、これが最後の手段です。

long型のnull型に変換したいときに問題が発生します。

明らかに、長い?クラスには解析メソッドがありません。

nullableのテンプレートタイプから解析メソッドを抽出するにはどうすればよいですか?

EDIT:

[Test] 
public void ConverterTNullable() 
{ 
    Assert.That((int?)1, Is.EqualTo(Converter<int?>.Convert(1))); 
    Assert.That((int?)2, Is.EqualTo(Converter<int?>.Convert(2.0d))); 
    Assert.That(3, Is.EqualTo(Converter<long>.Convert(3))); 

    Assert.That((object)null, Is.EqualTo(Converter<long?>.Convert(""))); 
    Assert.That((object)null, Is.EqualTo(Converter<long?>.Convert(null))); 
    Assert.That((object)null, Is.EqualTo(Converter<long?>.Convert(DBNull.Value))); 

    Assert.That((long)1, Is.EqualTo(Converter<long?>.Convert("1"))); 
    Assert.That((long)2, Is.EqualTo(Converter<long?>.Convert(2.0))); 
    Assert.That((long?)3, Is.EqualTo(Converter<long>.Convert(3))); 
} 

全体の機能::

/// <summary> 
/// Converts any compatible object to an instance of T. 
/// </summary> 
/// <param name="value">The value to convert.</param> 
/// <returns>The converted value.</returns> 
public static T Convert(object value) 
{ 
    if (value is T) 
    { 
     return (T)value; 
    } 

    Type t = typeof(T); 

    if (t == typeof(string)) 
    { 
     if (value is DBNull || value == null) 
     { 
      return (T)(object)null; 
     } 
     else 
     { 
      return (T)(object)(value.ToString()); 
     } 
    } 
    else 
    { 
     if (value is DBNull || value == null) 
     { 
      return default(T); 
     } 

     if (value is string && string.IsNullOrEmpty((string)value)) 
     { 
      return default(T); 
     } 

     try 
     { 
      return (T)value; 
     } 
     catch (InvalidCastException) 
     { 
     } 

     if (Nullable.GetUnderlyingType(t) != null) 
     { 
      t = Nullable.GetUnderlyingType(t); 
     } 

     MethodInfo parse = t.GetMethod("Parse", new Type[] { typeof(string) }); 

     if (parse != null) 
     { 
      object parsed = parse.Invoke(null, new object[] { value.ToString() }); 
      return (T)parsed; 
     } 
     else 
     { 
      throw new InvalidOperationException("The value you specified is not a valid " + typeof(T).ToString()); 
     } 
    } 
} 
+0

[ValueString](https://github.com/safakgur/value-string)について私は、あなたが行ったように、反射を使って解析する方法を見つけるものを書きました。次に、それを呼び出すラムダ式を作成し、コンパイルされたデリゲートをキャッシュするので、同じタイプに解析される将来のコールにはそのオーバーヘッドはありません。 –

答えて

0

私はこの少し追加:

if (Nullable.GetUnderlyingType(t) != null) 
{ 
    t = Nullable.GetUnderlyingType(t); 
} 

MethodInfo parse = t.GetMethod("Parse", new Type[] { typeof(string) }); 

みんなありがとうを!

+0

これは、null可能な型を返すには不十分で、基になる型を取り出して使用するだけです。 – Noldorin

+0

しかし、私がこれを行うときには、return(T)parse.Invoke(...)となります。 –

+0

ああ、私はそれがあなたのようにキャストできるようになるかどうかはわかりませんでした。けっこうだ。 – Noldorin

7

私は多分にTypeConverterを使用します。ここ

は、私が合格しようとしているテストの短い電池でありますこの場合、およびNullable.GetUnderlyingType()。例の途中で...

static void Main() 
    { 
     long? val1 = Parse<long?>("123"); 
     long? val2 = Parse<long?>(null); 
    } 

    static T Parse<T>(string value) 
    { 
     return (T) TypeDescriptor.GetConverter(typeof(T)) 
      .ConvertFrom(value); 
    } 
+0

btw - あなたが本当に基になる型を望むなら、Nullable.GetUnderlyingType(typeof(T))を試してください –

+0

@Marcこのコードはおそらく私の仕事の1日を節約しました。 –

+0

これは非常に役に立ちました – cordialgerm

2

これは仕事に適しています。 (それはあなたが望むものではないかもしれないけれども、コードは、簡単にするために拡張メソッドに埋め込まれている。)

public static T? ParseToNullable<T>(this string value) where T : struct 
{ 
    var parseMethod = typeof(T).GetMethod("Parse", new Type[] { typeof(string) }); 
    if (parseMethod == null) 
     return new Nullable<T>(); 

    try 
    { 
     var value = parseMethod.Invoke(null, new object[] { value.ToString() }); 
     return new Nullable<T>((T)value); 
    } 
    catch 
    { 
     return new Nullable<T>(); 
    } 
} 

さて、あなたはジェネリック型PARAMTER 自体をしたい場合はNULL可能タイプではなく、根本的な一つであることが、あなたが使用することができます(私は本当にこの利点は表示されません):

Nullable.GetUnderlyingType(typeof(T)) 

マルクGravellが提案されているように、それが唯一のコードにいくつかのマイナーな修正が必要となります。

+0

私は最後のビットを修正したいと思います...あなたのコードがあなたがヌル値を得ることは決してありません。あなたはおそらく、あなたのInvokeで例外のためにトラップする必要があります(つまり、TryParseはおそらくより良いメソッドです)、発生した場合はnullを返します。 –

+0

閉じるが、それほどではない。 私は実際に汎用コンバータを作成しようとしています。これをやろうとしているIm:Converter .Convert( "123") –

+0

@Adam:そうです、あなたは絶対に正しいです。 2回目にそれを見ると、はっきりと愚かでした。元の関数コードを書いているうちに多少気を散らしていたと思います。 :P – Noldorin

関連する問題