Я просто переглядаю розділ 4 C # в Depth, який стосується змінних типів, і я додаю розділ про використання оператора "as", який дозволяє писати:
object o = ...;
int? x = o as int?;
if (x.HasValue)
{
... // Use x.Value in here
}
Я подумав, що це дійсно охайно, і що це може підвищити продуктивність над еквівалентом C # 1, використовуючи "є", а потім - каст - адже саме нам потрібно лише один раз попросити динамічну перевірку типу, а потім просту перевірку значення .
Однак, мабуть, це не так. Нижче я включив зразок тестового додатка, який в основному підсумовує всі цілі числа в масиві об'єктів - але масив містить безліч нульових посилань і посилань рядків, а також цілих чисел у коробці. Базовий показник вимірює код, який вам доведеться використовувати в C # 1, код використовуючи оператор "як", і тільки для отримання рішення LINQ. На моє здивування, код C # 1 в цьому випадку в 20 разів швидший - і навіть LINQ-код (який, як би я очікував, буде повільніше, враховуючи ітератори), перемагає код "як".
Чи реалізація .NET isinst
для змінних типів просто повільна? Це додатковеunbox.any
причиною проблеми? Чи є інше пояснення цьому? На даний момент здається, що мені доведеться включити застереження від використання цього в ситуаціях, що залежать від продуктивності ...
Результати:
У ролях: 10000000: 121
Як: 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
для змінних типів. Цікаво, оскільки його не можна використовувати для інших типів цінності. Насправді, більш дивно.
as
намагається передати тип і якщо це не вдасться, він повернеться до нуля. Ви не можете встановити значення "значення" на нуль