Casting a używanie słowa kluczowego " as " w CLR

Podczas programowania interfejsów zauważyłem, że robię wiele odlewów lub konwersji typu obiektu.

Czy istnieje różnica między tymi dwoma metodami konwersji? Jeśli tak, czy istnieje różnica kosztów lub jak to wpływa na mój program?

public interface IMyInterface
{
    void AMethod();
}

public class MyClass : IMyInterface
{
    public void AMethod()
    {
       //Do work
    }

    // Other helper methods....
}

public class Implementation
{
    IMyInterface _MyObj;
    MyClass _myCls1;
    MyClass _myCls2;

    public Implementation()
    {
        _MyObj = new MyClass();

        // What is the difference here:
        _myCls1 = (MyClass)_MyObj;
        _myCls2 = (_MyObj as MyClass);
    }
}

Również, co jest" ogólnie " preferowaną metodą?

 396
Author: Frank V, 2009-01-30

18 answers

Odpowiedź poniżej linii została napisana w 2008 roku.

C # 7 wprowadził pattern matching, który w dużej mierze zastąpił operator as, Jak można teraz napisać:

if (randomObject is TargetType tt)
{
    // Use tt here
}

Zauważ, że tt jest nadal w zasięgu, ale nie jest definitywnie przypisany. (To jest definitywnie przypisane wewnątrz if ciała.) W niektórych przypadkach jest to nieco irytujące, więc jeśli naprawdę zależy ci na wprowadzeniu jak najmniejszej liczby zmiennych w każdym zakresie, możesz nadal chcieć użyć is a następnie Obsada.


Myślę, że żadna z odpowiedzi na razie (w momencie rozpoczęcia tej odpowiedzi!) naprawdę wyjaśniły, gdzie warto korzystać z których.

  • Nie rób tego:

    // Bad code - checks type twice for no reason
    if (randomObject is TargetType)
    {
        TargetType foo = (TargetType) randomObject;
        // Do something with foo
    }
    

    Nie tylko jest to sprawdzanie dwukrotnie, ale może to być sprawdzanie różnych rzeczy, jeśli randomObject jest polem, a nie zmienną lokalną. Jest możliwe, że" jeśli " przejdzie, ale wtedy cast się nie powiedzie, jeśli inny wątek zmieni wartość randomObject między dwa.

  • Jeśli randomObject naprawdę powinno być instancją TargetType, tzn. jeśli nie, to znaczy, że jest błąd, to casting jest właściwym rozwiązaniem. To natychmiast rzuca wyjątek, co oznacza, że żadna praca nie jest wykonywana przy błędnych założeniach, a wyjątek poprawnie pokazuje typ błędu.

    // This will throw an exception if randomObject is non-null and
    // refers to an object of an incompatible type. The cast is
    // the best code if that's the behaviour you want.
    TargetType convertedRandomObject = (TargetType) randomObject;
    
  • Jeśli randomObject może {[33] } być instancją TargetType i TargetType jest typem odniesienia, następnie użyj kodu jak to:

    TargetType convertedRandomObject = randomObject as TargetType;
    if (convertedRandomObject != null)
    {
        // Do stuff with convertedRandomObject
    }
    
  • Jeśli randomObject może być instancją TargetType i TargetType jest typem wartości, wtedy nie możemy użyć as z samym TargetType, ale możemy użyć typu nullable:

    TargetType? convertedRandomObject = randomObject as TargetType?;
    if (convertedRandomObject != null)
    {
        // Do stuff with convertedRandomObject.Value
    }
    

    (Uwaga: obecnie jest to w rzeczywistości wolniejsze niż jest + cast . Myślę, że jest bardziej elegancki i spójny, ale proszę bardzo.)

  • Jeśli naprawdę nie potrzebujesz przekonwertowanej wartości, ale musisz tylko wiedzieć, czy jest instancją TargetType, zatem operatorem is jest twój przyjaciel. W tym przypadku nie ma znaczenia, czy TargetType jest typem referencyjnym, czy typem wartości.

  • Mogą występować inne przypadki, w których is jest użyteczny (ponieważ możesz nie wiedzieć, czy T jest typem referencyjnym, czy nie, więc nie możesz go używać), ale są one stosunkowo niejasne.

  • Prawie na pewno użyłem is dla przypadku typu wartości do tej pory, nie myślałem o użyciu typu nullable i as razem :)


EDIT: zauważ, że żadne z powyższych nie mówi o wydajności, poza przypadkiem typu value, gdzie zauważyłem, że unboxing do typu nullable jest wolniejszy - ale spójny.

Naasking jest jednym z najbardziej rozpoznawalnych i najbardziej rozpoznawalnych w świecie gier komputerowych.]}
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] = "x";
            values[i + 2] = new object();
        }
        FindLengthWithIsAndCast(values);
        FindLengthWithIsAndAs(values);
        FindLengthWithAsAndNullCheck(values);
    }

    static void FindLengthWithIsAndCast(object[] values)        
    {
        Stopwatch sw = Stopwatch.StartNew();
        int len = 0;
        foreach (object o in values)
        {
            if (o is string)
            {
                string a = (string) o;
                len += a.Length;
            }
        }
        sw.Stop();
        Console.WriteLine("Is and Cast: {0} : {1}", len,
                          (long)sw.ElapsedMilliseconds);
    }

    static void FindLengthWithIsAndAs(object[] values)        
    {
        Stopwatch sw = Stopwatch.StartNew();
        int len = 0;
        foreach (object o in values)
        {
            if (o is string)
            {
                string a = o as string;
                len += a.Length;
            }
        }
        sw.Stop();
        Console.WriteLine("Is and As: {0} : {1}", len,
                          (long)sw.ElapsedMilliseconds);
    }

    static void FindLengthWithAsAndNullCheck(object[] values)        
    {
        Stopwatch sw = Stopwatch.StartNew();
        int len = 0;
        foreach (object o in values)
        {
            string a = o as string;
            if (a != null)
            {
                len += a.Length;
            }
        }
        sw.Stop();
        Console.WriteLine("As and null check: {0} : {1}", len,
                          (long)sw.ElapsedMilliseconds);
    }
}

Na moim laptopie, wszystkie one wykonują się w około 60ms. dwie rzeczy do odnotowania:

  • nie ma znaczenia różnica między nimi. (W rzeczywistości są sytuacje, w których as-plus-null-check zdecydowanie jest wolniejszy. Powyższy kod sprawia, że sprawdzenie typu jest łatwe, ponieważ jest dla zamkniętej klasy; jeśli sprawdzasz interfejs, balans wskazuje nieco na korzyść as-plus-null-check.)
  • Wszyscy są szalenie szybcy. To po prostu nie będzie wąskim gardłem w Twoim kodzie, chyba że naprawdę nie zrobisz niczego z wartościami potem.

Więc nie martwmy się o występ. Martwimy się poprawnością i konsekwencją.

Utrzymuję, że is-and-cast (lub is-and-as) są niebezpieczne w przypadku zmiennych, ponieważ typ wartości, do której się odnosi, może ulec zmianie z powodu innego wątku między testem a cast. To byłaby dość rzadka sytuacja - ale wolałbym mieć konwencję, z której mogę konsekwentnie korzystać.

Utrzymuję również, że As-then-null-check daje lepsze rozdzielenie obaw. Mamy jedną instrukcję, która próbuje konwersji, a następnie jedną instrukcję, która wykorzystuje wynik. Is-and-cast lub is-and-as wykonuje test i , a następnie {[33] } kolejną próbę przeliczenia wartości.

Mówiąc inaczej, czy ktokolwiek kiedykolwiek napisze:

int value;
if (int.TryParse(text, out value))
{
    value = int.Parse(text);
    // Use value
}

To coś w rodzaju tego, co robi is-and-cast-choć oczywiście w sposób tańszy.

 530
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-13 17:27:50

"Ponieważ" zwróci NULL, jeśli nie jest to możliwe do oddania.

Rzucanie przed spowoduje wyjątek.

Dla wydajności, podniesienie wyjątku jest zwykle bardziej kosztowne w czasie.

 75
Author: Patrick Desjardins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-10 18:37:55

Oto kolejna odpowiedź, z pewnym porównaniem IL. Rozważmy klasę:

public class MyClass
{
    public static void Main()
    {
        // Call the 2 methods
    }

    public void DirectCast(Object obj)
    {
        if ( obj is MyClass)
        { 
            MyClass myclass = (MyClass) obj; 
            Console.WriteLine(obj);
        } 
    } 


    public void UsesAs(object obj) 
    { 
        MyClass myclass = obj as MyClass; 
        if (myclass != null) 
        { 
            Console.WriteLine(obj);
        } 
    }
}

Teraz spójrz na IL każda metoda produkuje. Nawet jeśli kody op nic dla Ciebie NIE znaczą, możesz zobaczyć jedną zasadniczą różnicę-isinst jest wywoływany przez castclass w metodzie DirectCast. Więc dwa połączenia zamiast jednego.

.method public hidebysig instance void  DirectCast(object obj) cil managed
{
  // Code size       22 (0x16)
  .maxstack  8
  IL_0000:  ldarg.1
  IL_0001:  isinst     MyClass
  IL_0006:  brfalse.s  IL_0015
  IL_0008:  ldarg.1
  IL_0009:  castclass  MyClass
  IL_000e:  pop
  IL_000f:  ldarg.1
  IL_0010:  call       void [mscorlib]System.Console::WriteLine(object)
  IL_0015:  ret
} // end of method MyClass::DirectCast

.method public hidebysig instance void  UsesAs(object obj) cil managed
{
  // Code size       17 (0x11)
  .maxstack  1
  .locals init (class MyClass V_0)
  IL_0000:  ldarg.1
  IL_0001:  isinst     MyClass
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  brfalse.s  IL_0010
  IL_000a:  ldarg.1
  IL_000b:  call       void [mscorlib]System.Console::WriteLine(object)
  IL_0010:  ret
} // end of method MyClass::UsesAs

Słowo kluczowe isinst kontra castclass

Ten post na blogu ma przyzwoite porównanie między tymi dwoma sposobami. Jego podsumowanie jest:

    Isinst jest szybszy od castclass (choć tylko nieznacznie).]} Gdy trzeba było sprawdzać, czy konwersja się powiodła, isinst był znacznie szybszy niż castclass.]} Nie należy używać kombinacji isinst i castclass, ponieważ była ona znacznie wolniejsza niż najszybsza "bezpieczna" konwersja (ponad 12% wolniejsza)

Ja osobiście zawsze używam As, ponieważ jest łatwy do odczytania i jest zalecany przez rozwój. NET team (lub Jeffrey Richter w każdym razie)

 27
Author: Chris S,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-31 09:04:08

Jedną z bardziej subtelnych różnic między tymi dwoma jest to, że słowo kluczowe " as " nie może być użyte do odlewania, gdy zaangażowany jest operator odlewu:

public class Foo
{
    public string Value;

    public static explicit operator string(Foo f)
    {
        return f.Value;
    }

}

public class Example
{
    public void Convert()
    {
        var f = new Foo();
        f.Value = "abc";

        string cast = (string)f;
        string tryCast = f as string;
    }
}

To nie będzie kompilowane (chociaż myślę, że tak było w poprzednich wersjach) w ostatniej linii, ponieważ słowa kluczowe "as" nie biorą pod uwagę operatorów cast. Linia string cast = (string)f; działa jednak dobrze.

 18
Author: Patrik Hägne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-30 16:38:21

ponieważ nigdy nie rzuca wyjątku, jeśli nie może wykonać konwersji zwracając null zamiast tego (AS działa tylko na typach referencyjnych). Zatem użycie jako {[3] } jest zasadniczo równoważne

_myCls2 = _myObj is MyClass ? (MyClass)_myObj : null;

Odlewy w stylu C, z drugiej strony, rzucają wyjątek, gdy konwersja nie jest możliwa.

 12
Author: Anton Gogolev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-30 16:24:28

Nie do końca odpowiedź na twoje pytanie, ale to, co myślę, jest ważnym punktem związanym.

Jeśli programujesz do interfejsu, nie powinieneś mieć potrzeby rzucania. Mam nadzieję, że te odlewy są bardzo rzadkie. Jeśli nie, prawdopodobnie musisz przemyśleć niektóre z interfejsów.

 10
Author: toad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-30 16:26:52

Proszę zignorować Rady Jona Skeeta, re:unikaj wzorców testowania i odlewania, tj.:

if (randomObject is TargetType)
{
    TargetType foo = randomObject as TargetType;
    // Do something with foo
}

Pomysł, że to kosztuje więcej niż rzut i test zerowy, jest mitem :

TargetType convertedRandomObject = randomObject as TargetType;
if (convertedRandomObject != null)
{
    // Do stuff with convertedRandomObject
}
To mikro-optymalizacja, która nie działa. Przeprowadziłem kilka prawdziwych testów , i test-and-cast jest w rzeczywistości szybsze niż porównanie cast-and-null, i jest bezpieczniejsze, ponieważ nie masz możliwości uzyskania odniesienia null w zakresie poza if, jeśli cast zawiedzie.

Jeśli chcesz powód, dla którego test-and-cast jest szybszy, a przynajmniej nie wolniejszy, jest prosty i złożony powód.

Proste: nawet naiwne Kompilatory połączą dwie podobne operacje, takie jak test-and-cast, w jeden test i gałąź. cast-and-null-test może wymusić dwa testy i gałąź, jeden dla testu typu i konwersji na null po niepowodzeniu, jeden dla samego sprawdzenia null. Przynajmniej będą one zoptymalizowane do pojedynczego testu i gałęzi, więc test-and-cast nie będzie ani wolniejszy, ani szybciej niż test cast-and-null.

Complex: Dlaczego test-and cast jest szybszy: cast-and-null-test wprowadza inną zmienną do zewnętrznego zakresu, którą kompilator musi śledzić dla liveness, i może nie być w stanie zoptymalizować tej zmiennej w zależności od tego, jak skomplikowany jest twój przepływ sterowania. I odwrotnie, test-and-cast wprowadza nową zmienną tylko w rozdzielonym zakresie, więc kompilator wie, że zmienna jest martwa po zakończeniu zakresu, a więc może zoptymalizować alokację rejestru lepiej.

Więc proszę, niech ta rada" cast-and-null-test jest lepsza niż test-and-cast " umrze. Proszę. test-and-cast jest bezpieczniejszy i szybszy.
 9
Author: naasking,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-16 14:20:27

Jeśli cast się nie powiedzie, słowo kluczowe " as " Nie Rzuca wyjątku; zamiast tego ustawia zmienną na null (lub na jej domyślną wartość dla typów wartości).

 4
Author: TheSmurf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-30 16:23:36

To nie jest odpowiedź na pytanie, ale komentarz do kodu pytania przykład:

Zazwyczaj nie należy wyrzucać obiektu z np. IMyInterface do MyClass. Wspaniałą rzeczą w interfejsach jest to, że jeśli bierzesz obiekt jako dane wejściowe, które implementują interfejs, nie musisz przejmować się, jaki obiekt otrzymujesz.

Jeśli wrzucisz IMyInterface do MyClass, to już zakładasz, że otrzymujesz obiekt typu MyClass i nie ma sensu używać IMyInterface, ponieważ jeśli przesyłasz swój kod z innymi klasami, które implementują IMyInterface, złamie to Twój kod...

Teraz, moja rada: jeśli interfejsy są dobrze zaprojektowane można uniknąć wielu typecasting.

 4
Author: f3lix,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-30 16:36:49

Operator as może być używany tylko na typach referencyjnych, nie może być przeciążony i zwróci null, jeśli operacja się nie powiedzie. To nigdy nie spowoduje wyjątku.

Casting może być używany na wszystkich kompatybilnych typach, może być przeciążony i rzuci wyjątek, jeśli operacja się nie powiedzie.

Wybór, którego użyć, zależy od okoliczności. Przede wszystkim chodzi o to, czy chcesz rzucić wyjątek w przypadku nieudanej konwersji.

 3
Author: Jeffrey L Whitledge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-30 16:31:16

Moja odpowiedź dotyczy tylko prędkości w przypadkach, gdy nie sprawdzamy typu i nie sprawdzamy null po castingu. Dodałem dwa dodatkowe testy do kodu Jona Skeeta:

using System;
using System.Diagnostics;

class Test
{
    const int Size = 30000000;

    static void Main()
    {
        object[] values = new object[Size];

        for (int i = 0; i < Size; i++)
        {
            values[i] = "x";
        }
        FindLengthWithIsAndCast(values);
        FindLengthWithIsAndAs(values);
        FindLengthWithAsAndNullCheck(values);

        FindLengthWithCast(values);
        FindLengthWithAs(values);

        Console.ReadLine();
    }

    static void FindLengthWithIsAndCast(object[] values)
    {
        Stopwatch sw = Stopwatch.StartNew();
        int len = 0;
        foreach (object o in values)
        {
            if (o is string)
            {
                string a = (string)o;
                len += a.Length;
            }
        }
        sw.Stop();
        Console.WriteLine("Is and Cast: {0} : {1}", len,
                          (long)sw.ElapsedMilliseconds);
    }

    static void FindLengthWithIsAndAs(object[] values)
    {
        Stopwatch sw = Stopwatch.StartNew();
        int len = 0;
        foreach (object o in values)
        {
            if (o is string)
            {
                string a = o as string;
                len += a.Length;
            }
        }
        sw.Stop();
        Console.WriteLine("Is and As: {0} : {1}", len,
                          (long)sw.ElapsedMilliseconds);
    }

    static void FindLengthWithAsAndNullCheck(object[] values)
    {
        Stopwatch sw = Stopwatch.StartNew();
        int len = 0;
        foreach (object o in values)
        {
            string a = o as string;
            if (a != null)
            {
                len += a.Length;
            }
        }
        sw.Stop();
        Console.WriteLine("As and null check: {0} : {1}", len,
                          (long)sw.ElapsedMilliseconds);
    }
    static void FindLengthWithCast(object[] values)
    {
        Stopwatch sw = Stopwatch.StartNew();
        int len = 0;
        foreach (object o in values)
        {
            string a = (string)o;
            len += a.Length;
        }
        sw.Stop();
        Console.WriteLine("Cast: {0} : {1}", len,
                          (long)sw.ElapsedMilliseconds);
    }

    static void FindLengthWithAs(object[] values)
    {
        Stopwatch sw = Stopwatch.StartNew();
        int len = 0;
        foreach (object o in values)
        {
            string a = o as string;
            len += a.Length;
        }
        sw.Stop();
        Console.WriteLine("As: {0} : {1}", len,
                          (long)sw.ElapsedMilliseconds);
    }
}

Wynik:

Is and Cast: 30000000 : 88
Is and As: 30000000 : 93
As and null check: 30000000 : 56
Cast: 30000000 : 66
As: 30000000 : 46

Nie próbuj skupiać się na prędkości (tak jak ja), ponieważ wszystko to jest bardzo, bardzo szybkie.

 1
Author: CoperNick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-25 16:28:16

Poza tym wszystkim, co było już tutaj ujawnione, właśnie natknąłem się na praktyczną różnicę, myślę, że warto zauważyć, między wyraźnym odlewaniem

var x = (T) ...

Kontra za pomocą operatora as.

Oto przykład:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(GenericCaster<string>(12345));
        Console.WriteLine(GenericCaster<object>(new { a = 100, b = "string" }) ?? "null");
        Console.WriteLine(GenericCaster<double>(20.4));

        //prints:
        //12345
        //null
        //20.4

        Console.WriteLine(GenericCaster2<string>(12345));
        Console.WriteLine(GenericCaster2<object>(new { a = 100, b = "string" }) ?? "null");

        //will not compile -> 20.4 does not comply due to the type constraint "T : class"
        //Console.WriteLine(GenericCaster2<double>(20.4));
    }

    static T GenericCaster<T>(object value, T defaultValue = default(T))
    {
        T castedValue;
        try
        {
            castedValue = (T) Convert.ChangeType(value, typeof(T));
        }
        catch (Exception)
        {
            castedValue = defaultValue;
        }

        return castedValue;
    }

    static T GenericCaster2<T>(object value, T defaultValue = default(T)) where T : class
    {
        T castedValue;
        try
        {
            castedValue = Convert.ChangeType(value, typeof(T)) as T;
        }
        catch (Exception)
        {
            castedValue = defaultValue;
        }

        return castedValue;
    }
}

Podsumowując: GenericCaster2 nie będzie działać z typami struct. GenericCaster will.

 1
Author: Veverke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-20 15:10:27

Jeśli używasz Office PIAs kierując. NET Framework 4.X powinieneś użyć jako słowa kluczowego, w przeciwnym razie nie będzie kompilowane.

Microsoft.Office.Interop.Outlook.Application o = new Microsoft.Office.Interop.Outlook.Application();
Microsoft.Office.Interop.Outlook.MailItem m = o.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olMailItem) as Microsoft.Office.Interop.Outlook.MailItem;

Jeśli nie chcesz, aby to było możliwe, Skontaktuj się z nami.]}

Microsoft.Office.Interop.Outlook.MailItem m = (Microsoft.Office.Interop.Outlook.MailItem)o.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olMailItem);

Podczas targetowania. NET 4.X błędy to:

Błąd CS0656: brak kompilatora wymagany członek ' Microsoft.CSharp.RuntimeBinder.Binder.Convert"

Błąd CS0656: brak kompilatora wymagany członek "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create'

 1
Author: Olivier MATROT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-08 09:31:08

Słowo kluczowe as działa tak samo jak jawny rzut pomiędzy kompatybilnymi typami referencji z tą główną różnicą, że nie powoduje wyjątku, jeśli konwersja nie powiedzie się. Zamiast tego daje wartość null w zmiennej docelowej. Ponieważ wyjątki są bardzo kosztowne pod względem wydajności, uważa się ją za znacznie lepszą metodę odlewania.

 0
Author: Cerebrus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-30 16:26:23

To, co wybierzesz, zależy od tego, co jest wymagane. Preferuję wyraźny casting

IMyInterface = (IMyInterface)someobj;

Ponieważ jeśli obiekt powinien być typu IMyInterface, a nie jest - to zdecydowanie problem. Lepiej jest uzyskać błąd tak wcześnie, jak to możliwe, ponieważ dokładny błąd zostanie naprawiony zamiast naprawiać jego efekt uboczny.

Ale jeśli masz do czynienia z metodami, które akceptują object jako parametr, musisz sprawdzić jego dokładny typ przed wykonaniem dowolnego kodu. W takim przypadku as byłoby przydatne, więc można uniknąć InvalidCastException.

 0
Author: Oleg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-30 16:59:04

To zależy, czy chcesz sprawdzić null po użyciu "as", czy wolisz, aby Twoja aplikacja rzuciła wyjątek?

Moja zasada jest taka, że zawsze oczekuję, że zmienna będzie typu, którego oczekuję w momencie, w którym chcę użyć odlewu. Jeśli jest możliwe, że zmienna nie będzie rzucać na to, co chcę i jestem przygotowany do obsługi null z użyciem as, użyję as.

 0
Author: Darryl Braaten,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-30 16:59:47
 0
Author: juFo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-08 09:14:21

Problem OP ogranicza się do konkretnej sytuacji castingowej. Tytuł obejmuje znacznie więcej sytuacji.
Oto przegląd wszystkich istotnych sytuacji castingowych, które obecnie mogę myśleć:

private class CBase
{
}

private class CInherited : CBase
{
}

private enum EnumTest
{
  zero,
  one,
  two
}

private static void Main (string[] args)
{
  //########## classes ##########
  // object creation, implicit cast to object
  object oBase = new CBase ();
  object oInherited = new CInherited ();

  CBase oBase2 = null;
  CInherited oInherited2 = null;
  bool bCanCast = false;

  // explicit cast using "()"
  oBase2 = (CBase)oBase;    // works
  oBase2 = (CBase)oInherited;    // works
  //oInherited2 = (CInherited)oBase;   System.InvalidCastException
  oInherited2 = (CInherited)oInherited;    // works

  // explicit cast using "as"
  oBase2 = oBase as CBase;
  oBase2 = oInherited as CBase;
  oInherited2 = oBase as CInherited;  // returns null, equals C++/CLI "dynamic_cast"
  oInherited2 = oInherited as CInherited;

  // testing with Type.IsAssignableFrom(), results (of course) equal the results of the cast operations
  bCanCast = typeof (CBase).IsAssignableFrom (oBase.GetType ());    // true
  bCanCast = typeof (CBase).IsAssignableFrom (oInherited.GetType ());    // true
  bCanCast = typeof (CInherited).IsAssignableFrom (oBase.GetType ());    // false
  bCanCast = typeof (CInherited).IsAssignableFrom (oInherited.GetType ());    // true

  //########## value types ##########
  int iValue = 2;
  double dValue = 1.1;
  EnumTest enValue = EnumTest.two;

  // implicit cast, explicit cast using "()"
  int iValue2 = iValue;   // no cast
  double dValue2 = iValue;  // implicit conversion
  EnumTest enValue2 = (EnumTest)iValue;  // conversion by explicit cast. underlying type of EnumTest is int, but explicit cast needed (error CS0266: Cannot implicitly convert type 'int' to 'test01.Program.EnumTest')

  iValue2 = (int)dValue;   // conversion by explicit cast. implicit cast not possible (error CS0266: Cannot implicitly convert type 'double' to 'int')
  dValue2 = dValue;
  enValue2 = (EnumTest)dValue;  // underlying type is int, so "1.1" beomces "1" and then "one"

  iValue2 = (int)enValue;
  dValue2 = (double)enValue;
  enValue2 = enValue;   // no cast

  // explicit cast using "as"
  // iValue2 = iValue as int;   error CS0077: The as operator must be used with a reference type or nullable type
}
 0
Author: Tobias Knauss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-02 18:11:39