rksoftware

Visual Studio とか C# とかが好きです

キャストと as と TryParse

最近計測に凝っているので、キャストと as と TryParse も計測してみました。

キャストが一番早いのは当然として、as と TryParse が条件によって違う結果に。
int を object にしてからまた int に戻す際、as より TryParse の方が早いと。この経験がが役に立つ日がいつかあるのかわかりませんけれども。

Method Mean Error StdDev Median
CastInt 5.016 ns 0.1400 ns 0.2629 ns 5.047 ns
AsInt 24.595 ns 0.7971 ns 2.3501 ns 23.540 ns
TryParseInt 18.237 ns 0.3606 ns 0.3703 ns 18.239 ns
CastLong NA NA NA NA
AsLong 15.398 ns 0.3482 ns 0.5524 ns 15.303 ns
TryParseLong 24.741 ns 0.2888 ns 0.2836 ns 24.718 ns
CastDecimal NA NA NA NA
AsDecimal 17.747 ns 0.3871 ns 0.9992 ns 17.497 ns
TryParseDecimal 82.054 ns 1.6612 ns 2.2176 ns 81.831 ns
BenchmarkDotNet.Running.BenchmarkRunner.Run<Sample>(new BenchmarkDotNet.Configs.DebugInProcessConfig());

public class Sample
{
    [BenchmarkDotNet.Attributes.Benchmark]
    public void CastInt() => 1.Cast();
    [BenchmarkDotNet.Attributes.Benchmark]
    public void AsInt() => 1.As();
    [BenchmarkDotNet.Attributes.Benchmark]
    public void TryParseInt() => 1.TryParse();
    [BenchmarkDotNet.Attributes.Benchmark]
    public void CastLong() => 1L.Cast();
    [BenchmarkDotNet.Attributes.Benchmark]
    public void AsLong() => 1L.As();
    [BenchmarkDotNet.Attributes.Benchmark]
    public void TryParseLong() => 1L.TryParse();
    [BenchmarkDotNet.Attributes.Benchmark]
    public void CastDecimal() => 1m.Cast();
    [BenchmarkDotNet.Attributes.Benchmark]
    public void AsDecimal() => 1m.As();
    [BenchmarkDotNet.Attributes.Benchmark]
    public void TryParseDecimal() => 1m.TryParse();
}

static class MethodExtensions
{
    public static int Cast(this object i) => (int)i;
    public static int As(this object i) => i as int? ?? 0;
    public static int ConvertToInt(this object i) => Convert.ToInt32(i);
    public static int TryParse(this object i) => int.TryParse(i.ToString(), out int value) ? value : 0;
}

object 型の中身が int でないキャスト

object 型の中身が int でない int へのキャストは失敗するんですね。これは知りませんでした。C# 知らないことだらけです。

try
{
    var i = (int)(object)1; // これはできる
    Console.WriteLine(i);   // 1
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);  // ここには来ない
}
try
{
    var i = (int)1L;        // これはできる
    Console.WriteLine(i);   // 1
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);  // ここには来ない
}
try
{
    var i = (int)(object)1L;    // これはできない
    Console.WriteLine(i);       // ここには来ない
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);  // Unable to cast object of type 'System.Int64' to type 'System.Int32'.
}

エラーの内容

Unable to cast object of type 'System.Int64' to type 'System.Int32'.