null許容型を扱うC#in Depthの第4章を改訂し、 "as"演算子の使用に関するセクションを追加して、次のように記述できるようにします。
object o = ...;
int? x = o as int?;
if (x.HasValue)
{
... // Use x.Value in here
}
私はこれが本当に素晴らしいと思い、 "is"に続けてキャストを使用することで、C#1と同等のパフォーマンスを向上させることができると思いました。 。
ただし、そうではないようです。以下にサンプルテストアプリを含めました。これは基本的にオブジェクト配列内のすべての整数を合計しますが、配列には多くのnull参照と文字列参照、およびボックス化された整数が含まれています。ベンチマークは、C#1で使用する必要があるコード、「as」演算子を使用するコード、およびLINQソリューションのキックを測定します。驚いたことに、この場合、C#1コードは20倍高速です。また、LINQコード(イテレータが関与していることを考えると、遅くなることが予想されていました)でも「as」コードよりも優れています。
isinst
null許容型の.NET実装は本当に遅いのですか?unbox.any
問題の原因は追加ですか?これには別の説明がありますか?現時点では、パフォーマンスに敏感な状況でこれを使用することに対する警告を含める必要があるように思われます...
結果:
キャスト:10000000:121
As:10000000:2211
LINQ:10000000:2143
コード:
using System;
using System.Diagnostics;
using System.Linq;
class Test
{
const int Size = 30000000;
static void Main()
{
object[] values = new object[Size];
for (int i = 0; i < Size - 2; i += 3)
{
values[i] = null;
values[i+1] = "";
values[i+2] = 1;
}
FindSumWithCast(values);
FindSumWithAs(values);
FindSumWithLinq(values);
}
static void FindSumWithCast(object[] values)
{
Stopwatch sw = Stopwatch.StartNew();
int sum = 0;
foreach (object o in values)
{
if (o is int)
{
int x = (int) o;
sum += x;
}
}
sw.Stop();
Console.WriteLine("Cast: {0} : {1}", sum,
(long) sw.ElapsedMilliseconds);
}
static void FindSumWithAs(object[] values)
{
Stopwatch sw = Stopwatch.StartNew();
int sum = 0;
foreach (object o in values)
{
int? x = o as int?;
if (x.HasValue)
{
sum += x.Value;
}
}
sw.Stop();
Console.WriteLine("As: {0} : {1}", sum,
(long) sw.ElapsedMilliseconds);
}
static void FindSumWithLinq(object[] values)
{
Stopwatch sw = Stopwatch.StartNew();
int sum = values.OfType<int>().Sum();
sw.Stop();
Console.WriteLine("LINQ: {0} : {1}", sum,
(long) sw.ElapsedMilliseconds);
}
}
as
、null許容型で使用できることを学びました。他の値タイプでは使用できないため、興味深い。実際、もっと意外です。
as
て、型にキャストしようとし、失敗した場合はnullを返します。値タイプをnullに設定することはできません