Ich überarbeite gerade Kapitel 4 von C # in Depth, das sich mit nullbaren Typen befasst, und füge einen Abschnitt über die Verwendung des Operators "as" hinzu, in dem Sie schreiben können:
object o = ...;
int? x = o as int?;
if (x.HasValue)
{
... // Use x.Value in here
}
Ich fand das wirklich ordentlich und konnte die Leistung gegenüber dem C # 1-Äquivalent verbessern, indem "is" gefolgt von einer Besetzung verwendet wurde. Schließlich müssen wir auf diese Weise nur einmal nach einer dynamischen Typprüfung und dann nach einer einfachen Wertprüfung fragen .
Dies scheint jedoch nicht der Fall zu sein. Ich habe unten eine Beispiel-Test-App eingefügt, die im Grunde alle Ganzzahlen in einem Objektarray summiert - aber das Array enthält viele Nullreferenzen und Zeichenfolgenreferenzen sowie Ganzzahlen in Kästchen. Der Benchmark misst den Code, den Sie in C # 1 verwenden müssten, den Code mit dem Operator "as" und nur für Kicks eine LINQ-Lösung. Zu meinem Erstaunen ist der C # 1-Code in diesem Fall 20-mal schneller - und sogar der LINQ-Code (von dem ich angesichts der beteiligten Iteratoren erwartet hätte, dass er langsamer ist) schlägt den "as" -Code.
Ist die .NET-Implementierung isinst
für nullfähige Typen nur sehr langsam? Ist es das zusätzliche unbox.any
, das das Problem verursacht? Gibt es eine andere Erklärung dafür? Im Moment scheint es, als müsste ich eine Warnung davor einfügen, dies in leistungsempfindlichen Situationen zu verwenden ...
Ergebnisse:
Besetzung: 10000000: 121
As: 10000000: 2211
LINQ: 10000000: 2143
Code:
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
nullbare Typen verwenden können. Interessant, da es nicht für andere Werttypen verwendet werden kann. Eigentlich überraschender.
as
versuchen Sie, in einen Typ umzuwandeln, und wenn dies fehlschlägt, wird null zurückgegeben. Sie können