Я просто пересматриваю четвертую главу C # in Depth, которая посвящена обнуляемым типам, и добавляю раздел об использовании оператора «as», который позволяет писать:
object o = ...;
int? x = o as int?;
if (x.HasValue)
{
... // Use x.Value in here
}
Я подумал, что это действительно здорово, и что это может улучшить производительность по сравнению с эквивалентом C # 1, используя «is» с последующим приведением - в конце концов, таким образом, нам нужно только один раз запросить динамическую проверку типа, а затем простую проверку значения ,
Однако, похоже, это не так. Ниже я включил пример тестового приложения, которое в основном суммирует все целые числа в массиве объектов, но массив содержит множество пустых ссылок и ссылок на строки, а также целые числа в штучной упаковке. Тест измеряет код, который вы должны использовать в 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
попытайтесь привести к типу, и если он потерпит неудачу, он вернет ноль. Вы не можете установить типы значений в null