2016-06-24 10 views
6

String型から汎用型に変換しようとしています。ジェネリック型がそうでのInt32、Int64型、ブール型、ダブルとなります...私は2つのアプローチを試してみました:汎用型コンバータ - TypeConverterまたはConvert.ChangeType

public static Boolean TryParse<T>(String source, out T value) { 

    TypeConverter converter = TypeDescriptor.GetConverter(typeof(T)); 

    try { 

    value = (T)converter.ConvertFromString(source); 
    return true; 

    } catch { 

    value = default(T); 
    return false; 

    } 

} 

public static Boolean TryChangeType<T>(Object source, out T value) { 

    try { 

    Type type = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T); 

    value = (T)Convert.ChangeType(source, type); 
    return true; 

    } catch { 

    value = default(T); 
    return false; 

    } 

} 

それはオブジェクトを受け入れるように、第2の1がより一般的です。

また、文化問題を解決するためにConvert.ChangeTypeで使用されるTryChangeTypeにIFormatProviderを渡すことを検討しています。

2番目のアプローチをよりよく考えていますか?

どのようにしてコードを改善できますか?

+0

[TypeConverterとConvert対TargetType.Parseの可能な複製](http://stackoverflow.com/questions/7010669/typeconverter-vs-convert-vs-targettype-parse) –

答えて

2

あなたの最初の例では、事前に​​とCanConvertFrom()を呼び出してtry catchブロックを取り除くことができます。

public static bool TryParse<T>(string source, out T value) 
{ 
    TypeConverter converter = TypeDescriptor.GetConverter(typeof (T)); 
    if (converter.CanConvertTo(typeof (T)) && converter.CanConvertFrom(typeof (string))) 
    { 
     value = (T)converter.ConvertFromString(source); 
     return true; 
    } 
    else 
    { 
     value = default (T); 
     returns false; 
    } 
} 

2番目の例では、それをさらに汎用化してジェネリック型を渡すのはなぜですか?

ConvertインターフェイスがIConvertibleインターフェイスを実装しているかどうかを確認できるようにする場合にのみ機能します。一方、それは変換が可能であることを保証しません。

 public static bool TryChangeType<T, TR>(T input, out TR output) where T : IConvertible 
    { 
     bool result = false; 
     try 
     { 
      Type type = Nullable.GetUnderlyingType(typeof(TR)); 
      output = (TR)Convert.ChangeType(input, type); 
      result = true; 
     } 
     catch(Exception) 
     { 
      output = default(TR); 
     } 
     return result; 
    } 

だけが知っている例外をキャッチすることがいいだろう:

  catch(InvalidCastException) 
     { 
      output = default(TR); 
      //Conversion is not unsupported 
     } 
      catch(FormatException) 
     { 
      output = default(TR); 
      //string input value was in incorrect format 
     } 
      catch(InvalidCastException) 
     { 
      output = default(TR); 
      //Conversion is not unsupported 
     } 
      catch(OverflowException) 
     { 
      output = default(TR); 
      //narrowing conversion between two numeric types results in loss of data 
     } 

これは完全に質問に答えるないかもしれませんが、私は、なぜないと思ったので、あなたが可能な改善を求めました。

+0

はい、これはもっと一般的です。良い提案。 –

0

最初の例では、TypeDescriptor.GetConverter(Type)は例外をスローする可能性があるため、tryブロックに移動してください。私はあなたの2つのアプローチから個人的に試してみません、私は2番目のアプローチが好きです。

This postは、try/catchなしで変換可能性のテストの例を示し、パフォーマンスのメリットを主張しています。

+0

興味深い... Try Catchブロックを取り除くことは、私がやりたかったことでした...可能であるかどうか分かりませんでした。 –

1

2番目のものはIConvertibleタイプのみに適用されます。これはあなたが望むものであるならば、あなたは(ChangeTypeはとにかく非コンバーチブルタイプの例外がスローされます)あまりにも、制約を適用する場合があります

public static Boolean TryChangeType<T>(Object source, out T value) 
    where T : IConvertible 
{ 
    // ... 
} 

最初のものは、より一般的で、TypeConverterをするときに使用されます。 NETコンポーネントモデルを使用する必要があります。たとえば、デザイナでは、型コンバーターを使用してプロパティグリッドの文字列から値を変換します。しかし、あなたは、あまりにも、ここに小さな追加のチェックを追加する必要があります。また

if (!converter.CanConvertFrom(typeof(string))) 
    return false; 

、私はあなたが別の地域設定とのトラブルをしたくない場合は、浮動小数点値の場合には(ConvertFromInvariantStringメソッドを使用する必要があることを言及します、たとえば...

+0

良いヒントであるConvertFromInvariantStringについて...私はdouble型の変換に問題がありました。または "、" ...しかし、私はIFormatProviderを渡すことができる2番目のオプションを使用して...右の2番目の例では、その問題を解決する? –

+0

はい、特定の文化を使用すると問題も解決します。 Btw、ここでは 'object'ソースから変換することもできます。 'CanConvertFrom(Type)'メソッドを使うだけです。 – taffer