はじめに
今回はTypeConverter.ConvertFromString
とC#11から導入されたIParsable<TSelf>
を紹介したいと思います。
概要
例えばstring
からジェネリックのT
の値にパースしたいとします。
public static bool TryParse<T>(string value, out T result) { // TODO: valueからresultにParseをする }
ぱっと見型スイッチで頑張るみたいなものしか思いつかなかったのですが、これを実現する方法について調べたので書き残しておきたいと思います。
C#11以前
TypeConverter.ConvertFromString
を用いることで指定したテキストをオブジェクトに変換できます。
learn.microsoft.com
public static bool TryParse<T>(string value, out T result) where T : struct { try { // TypeConverterが型をサポートしていないと「System.NotSupportedException」が投げられる TypeConverter converter = TypeDescriptor.GetConverter(typeof(T)); // Parseに失敗すると「System.ArgumentException」が投げられる result = (T)(converter.ConvertFromString(value) ?? default(T)); return true; } catch { result = default; return false; } }
正直エラーが投げられるのは微妙ですね。TryConvertFromString
みたいなメソッドもなければ、パースできるか判定するメソッドもありません。
パフォーマンス的にも正直微妙そうです。
C#11以降
IParsable<T>
というインターフェースが導入されました。
public interface IParsable<TSelf> where TSelf : IParsable<TSelf>? { static abstract TSelf Parse(string s, IFormatProvider? provider); static abstract bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(returnValue: false)] out TSelf result); }
public static bool TryParse<T>(string value, out T result) where T : IParsable<T> { return T.TryParse(value, null, out result); }
こちらはかなり実用的だと思います。
パフォーマンス的な話
特にC#11
以前の場合の手法はパフォーマンスが悪そうです。具体的な型を引数にとったメソッドを複数生やした方が良いかもしれません。
public static bool TryParseInt(string value, out int result) { return int.TryParse(value, out result); } // ...