Leistung überraschung mit "als" und nullable-Typen

Ich bin nur eine überarbeitung Kapitel 4 in C# in der Tiefe, die sich mit nullable-Typen, und ich bin das hinzufügen einen Abschnitt über die Verwendung des "as" - operator, welcher Ihnen erlaubt, zu schreiben:

object o = ...;
int? x = o as int?;
if (x.HasValue)
{
    ... //Use x.Value in here
}

Dachte ich, das war wirklich nett, und es könnte verbessern Sie die Leistung über die C# 1 entspricht, mit "" gefolgt von einer Besetzung - nach allen, diesen Weg, wir brauchen Sie nur zu Fragen für die dynamische Typ-überprüfung einmal, und dann einen einfachen Wert überprüfen.

Dies scheint nicht der Fall zu sein, jedoch. Ich habe einen Probe-test-app unter, die im Grunde die Summen die zahlen in einem object-array, aber das array enthält eine Menge von null-Referenzen und die string-Referenzen als auch als boxed-Ganzzahlen. Der benchmark misst den code müssten Sie zur Verwendung in C# 1, den code über die "wie" - operator, und einfach nur aus Spaß eine LINQ Lösung. Zu meinem Erstaunen, die C# 1 code 20 mal schneller-in diesem Fall - und auch die LINQ-code (was ich erwartet habe, langsamer zu sein, da die Iteratoren beteiligt) schlägt das "wie" code.

Ist .NET-Implementierung der isinst für nullable-Typen nur sehr langsam? Ist es das zusätzliche unbox.any, die das problem verursacht? Gibt es eine andere Erklärung dafür? Im moment fühlt es sich wie ich bin zu haben, um eine Warnung gegen die Verwendung dieser Leistung in heiklen Situationen...

Ergebnisse:

Darsteller: 10000000 : 121
Als: 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);
    }
}
Warum nicht Blick auf die jitted code? Auch VS-debugger können zeigen.
Ich bin nur neugierig, hast du den test mit CLR 4.0?
Guter Punkt. Tun, an einem gewissen Punkt (obwohl dies nicht in VS im moment 🙂 @divo: ja, und es ist schlimmer, rundum. Aber das ist dann in der beta, also kann es eine Menge von debugging-code drin.
Heute habe ich gelernt, die Sie verwenden können as auf null festlegbaren Typen. Interessant, wie es kann nicht verwendet werden, die auf andere Werttypen. Eigentlich mehr überraschend.
es macht Sinn für es nicht auf den Wert-Typen. Denke, über, as versucht zu werfen, um einen Typ und wenn es dann nicht den Wert null zurück. Sie können nicht von Wert-Typen zu null

InformationsquelleAutor Jon Skeet | 2009-10-17

Schreibe einen Kommentar