IParsable<TSelf>
というインターフェースがある。(.NET 7~)
https://learn.microsoft.com/ja-jp/dotnet/api/system.iparsable-1?view=net-8.0
実装している型は、Parse
メソッドとTryParse
メソッドを持つ。
例えば以下のように使える。
public T ConvertByIParsable<T>(string str) where T : IParsable<T> { return T.Parse(str, default); }
このインターフェース、.NET 7 においては数値の型が備えていた。
そして、.NET 8 において、string
とbool
も備えるようになった。(今回は関係ないがSystem.Net.IPAddress
も)
このため、数値も文字列も真偽値も一緒くたというような、例えば以下の記事のような場合に、一括でIParsable<TSelf>
として投げ込めるようになった。
・【C#】文字列から<T>型への汎用コンバート - てくメモ
上記記事のTypeDescriptor
・型での分岐に、今回IParsable<TSelf>
を並べて比較。(BenchmarkDotNet)
ベンチマークコード折りたたみ
private readonly string[] lines = [ "12", "12.3", "c", "str", "true" ]; public T ConvertByDescriptor<T>(string str) { var obj = TypeDescriptor.GetConverter(typeof(T)).ConvertFromString(str); return obj is T result ? result : throw new NotSupportedException(); } public T ConvertByTypeSwitch<T>(string str) { if (typeof(T) == typeof(int)) { return (T)(object)int.Parse(str); } else if (typeof(T) == typeof(double)) { return (T)(object)double.Parse(str); } else if (typeof(T) == typeof(char)) { return (T)(object)char.Parse(str); } else if (typeof(T) == typeof(string)) { return (T)(object)str; } else if (typeof(T) == typeof(bool)) { return (T)(object)bool.Parse(str); } throw new NotSupportedException(); } public T ConvertByIParsable<T>(string str) where T : IParsable<T> { return T.Parse(str, default); } [Benchmark] public string ByTypeDescriptor() { var n = ConvertByDescriptor<int>(lines[0]); var d = ConvertByDescriptor<double>(lines[1]); var c = ConvertByDescriptor<char>(lines[2]); var s = ConvertByDescriptor<string>(lines[3]); var b = ConvertByDescriptor<bool>(lines[4]); return $"{n}, {d}, {c}, {s}, {b}"; } [Benchmark] public string ByTypeSwitch() { var n = ConvertByTypeSwitch<int>(lines[0]); var d = ConvertByTypeSwitch<double>(lines[1]); var c = ConvertByTypeSwitch<char>(lines[2]); var s = ConvertByTypeSwitch<string>(lines[3]); var b = ConvertByTypeSwitch<bool>(lines[4]); return $"{n}, {d}, {c}, {s}, {b}"; } [Benchmark] public string ByIParsable() { var n = ConvertByIParsable<int>(lines[0]); var d = ConvertByIParsable<double>(lines[1]); var c = ConvertByIParsable<char>(lines[2]); var s = ConvertByIParsable<string>(lines[3]); var b = ConvertByIParsable<bool>(lines[4]); return $"{n}, {d}, {c}, {s}, {b}"; }
Method | Mean | Error | StdDev | Gen0 | Allocated | ----------------- |-----------:|---------:|---------:|-------:|----------:| ByTypeDescriptor | 1,250.2 ns | 612.1 ns | 33.55 ns | 0.0534 | 168 B | ByTypeSwitch | 309.9 ns | 242.1 ns | 13.27 ns | 0.0229 | 72 B | ByIParsable | 292.8 ns | 197.6 ns | 10.83 ns | 0.0229 | 72 B |
IParsable<TSelf>.Parse
メソッドはいわゆるインターフェースの静的仮想メンバーであり、パフォーマンス的憂いもなし。