2008-12-11 18 views
20

Podczas używania słowa kluczowego "as" w języku C# do rzutowania, które się nie powiedzie, zostanie zwrócona wartość null. Co dzieje się w tle? Czy po prostu tłumi się wyjątek, więc nie muszę pisać kodu obsługi na wypadek awarii?Skutki związane z wydajnością przesyłu C#

Interesuje mnie jego charakterystyka wydajnościowa w porównaniu z typową obsadą zapakowaną w try-catch.

Odpowiedz

49

Używa instrukcji IL isinst do wykonywania rzutowania zamiast instrukcji castclass, która jest używana podczas rzutowania. Jest to specjalna instrukcja, która wykonuje rzut, jeśli jest ważna, inaczej pozostawia na stosie null, jeśli nie jest. Więc nie, to nie tylko tłumi wyjątek, i jest o rząd wielkości szybszy niż to robi.

pamiętać, że istnieją pewne różnice w zachowaniu między instrukcją isinst i castclass - z których głównym jest, że isinst nie uwzględnia operatorów odlewanych zdefiniowanych przez użytkownika, to tylko uważa hierarchii dziedziczenia, na przykład bezpośrednie jeśli zdefiniować następujące dwie klasy bez hierarchii dziedziczenia, ale wyraźnego operatora Obsada:

class A 
{ 
    public int Foo; 
} 

class B 
{ 
    public int Foo; 

    public static explicit operator B(A a) 
    { 
     return new B { Foo = a.Foo }; 
    } 
} 

Następnie dodaje się uda:

var a = new A { Foo = 3 }; 
var b = (B)a; 
Console.WriteLine(b.Foo); // prints 3 

Jednak następujące nie kompilacji z błędem „nie można przekonwertować Typ „a” do „B” poprzez konwersję odniesienia, boks konwersji, unboxing nawrócenia, przemiany pakowy lub null konwersji typu”

var a = new A { Foo = 3 }; 
var b = a as B; 

Więc jeśli masz y skonfigurowane przez użytkownika konfiguracje rzutowania (które zazwyczaj są złym pomysłem na typy odniesienia, z tego i innych powodów), powinieneś być świadomy tej różnicy.

+0

Jaki jest powód, dla którego nie zostanie skompilowany? Myślałem, że "as" jest oceniane tylko podczas wykonywania kodu? Czy to oznacza, że ​​kompilator sprawdza również przesyłanie podczas kompilacji? – faulty

+0

@faulty - kompilator statycznie sprawdza rzuty, jeśli to możliwe, aby upewnić się, że nie piszesz kodu, który nie może się powieść (nie pamiętam, czy było to ostrzeżenie lub błąd, ponieważ zawsze mam ostrzeżenia, gdy błędy są włączone). –

7

I dodać do Grega doskonałą postu ...

Po raz pierwszy nowy typ jest określany w czasie wykonywania, CLR ładuje do pamięci struktura zwana COREINFO_CLASS_STRUCT (lub coś podobnego), który zawiera, między innymi, wskaźnik do obiektu COREINFO_CLASS_STRUCT dla klasy bazowej, z której ten obiekt pochodzi ... W ten sposób tworzona jest połączona lista obiektów COREINFO_CLASS_STRUCT dla łańcucha dziedziczenia dla typu, która kończy się COREINFO_CLASS_STRUCT dla. Kiedy wykonasz isinst, (lub jest to analogiczna metoda castclass), po prostu musisz znaleźć strukturę pamięci COREINFO_CLASS_STRUCT dla konkretnego typu badanego obiektu i przechodzić przez tę połączoną listę, aby sprawdzić, czy Typ, na który próbujesz rzucić jest w Lista.

Zawiera również wskaźnik do oddzielnej tablicy zawierającej wszystkie interfejsy implementowane przez typ, które należy przeszukiwać oddzielnie, jeśli próbujesz rzutować na interfejs.

Powiązane problemy