Direct casting vs operator "as"?

Rozważ następujący kod:

void Handler(object o, EventArgs e)
{
   // I swear o is a string
   string s = (string)o; // 1
   //-OR-
   string s = o as string; // 2
   // -OR-
   string s = o.ToString(); // 3
}

Jaka jest różnica między trzema typami castingu(dobrze, trzeci nie jest castingiem, ale masz zamiar). Który z nich powinien być preferowany?

 753
Author: Kirill Kobelev, 2008-09-25

16 answers

string s = (string)o; // 1

Throws InvalidCastException if o is not a string. W przeciwnym razie przyporządkowuje o do s, nawet jeśli o jest null.

string s = o as string; // 2

Przypisuje null do s Jeśli o nie jest string lub jeśli o jest null. Z tego powodu nie można go używać z typami wartości (operator nigdy nie może zwrócić null w takim przypadku). W przeciwnym razie przyporządkowuje o do s.

string s = o.ToString(); // 3

Powoduje Nullreferencexception Jeśli o jest null. Przypisuje cokolwiek o.ToString() zwraca s, nie matter what type o is.


Użyj 1 dla większości konwersji - jest to proste i proste. Zwykle prawie nigdy nie używam 2, ponieważ jeśli coś nie jest odpowiednim typem, Zwykle oczekuję wystąpienia wyjątku. Widziałem tylko potrzebę takiego typu funkcji return-null z źle zaprojektowanymi bibliotekami, które używają kodów błędów (np. return null = error, zamiast używania WYJĄTKÓW).

3 nie jest obsadą i jest tylko wywołaniem metody. Użyj go, gdy potrzebujesz Sznurka reprezentacja obiektu non-string.

 874
Author: Sander,
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
2016-05-10 16:23:03
  1. string s = (string)o; użyj, gdy coś powinno zdecydowanie być inną rzeczą.
  2. string s = o as string; Użyj, gdy coś może być innym rzecz.
  3. string s = o.ToString(); Użyj, gdy nie dbasz o to, co jest, ale po prostu chcesz użyć dostępna reprezentacja łańcuchów.
 367
Author: Quibblesome,
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
2019-05-26 08:26:19

To naprawdę zależy od tego, czy wiesz, czy o jest ciągiem i co chcesz z nim zrobić. Jeśli twój komentarz oznacza, że o naprawdę naprawdę jest ciągiem, wolałbym prosty (string)o Obsada - raczej nie zawiedzie.

Największą zaletą używania prostego rzutu jest to, że gdy się nie powiedzie, otrzymujesz InvalidCastException, który mówi ci, co poszło nie tak.

Z operatorem as, Jeśli o nie jest ciągiem znaków, s jest ustawione na null, co jest przydatne, jeśli nie jesteś pewien i chcesz przetestować s:

string s = o as string;
if ( s == null )
{
    // well that's not good!
    gotoPlanB();
}

Jeśli jednak nie wykonasz tego testu, użyjesz s później i wyrzucisz NullReferenceException. Te wydają się być bardziej powszechne i lot trudniejsze do wytropienia, gdy zdarzy się na wolności, ponieważ prawie każda linia dereferuje zmienną i może rzucić jedną. Z drugiej strony, jeśli próbujesz obsadzić typ wartości (dowolne prymitywne struktury, takie jak DateTime ), musisz użyć prostego obsady - as nie zadziała.

W specjalnym przypadku konwersji do ciągu znaków, każdy obiekt ma ToString, więc twoja trzecia metoda może być w porządku, jeśli o nie jest null i myślisz, że metoda ToString może zrobić to, co chcesz.

 31
Author: Blair Conrad,
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
2008-09-25 10:22:16

Jeśli już wiesz, do jakiego typu może rzucać, użyj c-style cast:

var o = (string) iKnowThisIsAString; 

Zauważ, że tylko z obsadą w stylu C możesz wykonać wyraźny przymus typu.

Jeśli nie wiesz, czy jest to żądany typ i zamierzasz go użyć, użyj jako słowa kluczowego:

var s = o as string;
if (s != null) return s.Replace("_","-");

//or for early return:
if (s==null) return;

Zauważ, że as nie wywoła żadnych operatorów konwersji typu. Będzie ona inna niż null tylko wtedy, gdy obiekt nie jest null i natywnie określonego typu.

Użyj ToString (), aby uzyskać czytelna dla człowieka reprezentacja łańcuchowa dowolnego obiektu, nawet jeśli nie może zostać rzucona na łańcuch.

 9
Author: Mark Cidade,
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
2008-09-25 10:41:43

Słowo kluczowe as jest dobre w asp.net podczas korzystania z metody FindControl.

Hyperlink link = this.FindControl("linkid") as Hyperlink;
if (link != null)
{
     ...
}

Oznacza to, że możesz operować na wpisanej zmiennej, a następnie rzucać ją z object, tak jak w przypadku bezpośredniego rzucania:

object linkObj = this.FindControl("linkid");
if (link != null)
{
     Hyperlink link = (Hyperlink)linkObj;
}

To nie jest wielka rzecz, ale zapisuje linie kodu i przypisywanie zmiennych, plus jest bardziej czytelny

 7
Author: Glenn Slaven,
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
2008-09-25 11:17:27

'as' opiera się na 'is', które jest słowem kluczowym, które sprawdza w czasie wykonywania, czy obiekt jest zgodny polimorficznie (zasadniczo, jeśli można wykonać rzut) i zwraca null, jeśli sprawdzenie się nie powiedzie.

Te dwa są równoważne:

Użycie "as":

string s = o as string;

Użycie "is":

if(o is string) 
    s = o;
else
    s = null;

Przeciwnie, obsada w stylu c jest wykonywana również podczas wykonywania, ale rzuca wyjątek, jeśli nie można wykonać obsady.

Aby dodać ważny fakt:

Słowo kluczowe 'as' działa tylko z typy referencyjne. Nie możesz zrobić:

// I swear i is an int
int number = i as int;

W tych przypadkach trzeba użyć castingu.

 6
Author: Sergio Acosta,
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
2008-09-25 10:21:46

2 jest przydatny do odlewania do typu pochodnego.

Załóżmy, że a jest zwierzęciem:

b = a as Badger;
c = a as Cow;

if (b != null)
   b.EatSnails();
else if (c != null)
   c.EatGrass();

Dostaniea nakarmione minimum rzutów.

 5
Author: Joel in Gö,
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
2008-09-25 10:31:39

Według eksperymentów prowadzonych na tej stronie: http://www.dotnetguru2.org/sebastienros/index.php/2006/02/24/cast_vs_as

(Na tej stronie pojawiają się czasami błędy "nielegalnych referrerów" , więc po prostu odśwież, jeśli tak się stanie)

Wniosek jest taki, że operator " as " jest zwykle szybszy od obsady. Czasami o wiele razy szybciej, czasami po prostu ledwo szybciej.

I peronsonally rzecz "as" jest również bardziej czytelne.

Więc, ponieważ jest zarówno szybszy, jak i" bezpieczniejszy " (nie throw exception), i ewentualnie łatwiejsze do odczytania, polecam używanie" as " cały czas.

 5
Author: Brady Moritz,
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
2010-08-15 18:36:54

"(string)o " spowoduje InvalidCastException, ponieważ nie ma bezpośredniego oddania.

"o As string" spowoduje, że s będzie referencją null, a nie zostanie wyrzucony wyjątek.

"o. ToString ()" nie jest cast żadnego rodzaju per-se, jest to metoda zaimplementowana przez obiekt, a więc w taki czy inny sposób przez każdą klasę w. Net, która "robi coś" z instancją klasy, do której jest wywołana i zwraca łańcuch znaków.

Nie zapomnij, że do konwersji na string, jest też nawrócenie.ToString (someType instanceOfThatType), gdzie someType jest jednym z zestawów typów, zasadniczo typów bazowych frameworków.

 4
Author: Rob,
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
2012-01-13 10:28:22

Wszystkie odpowiedzi są dobre, jeśli mogę coś dodać: Aby bezpośrednio użyć metod i właściwości string (np. ToLower) nie można napisać:

(string)o.ToLower(); // won't compile

Możesz tylko napisać:

((string)o).ToLower();

Ale mógłbyś zamiast tego napisać:

(o as string).ToLower();

Opcja as jest bardziej czytelna (przynajmniej moim zdaniem).

 3
Author: BornToCode,
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-04-03 14:28:13
string s = o as string; // 2

Jest preferowany, ponieważ pozwala uniknąć kary za wykonanie podwójnego rzutu.

 3
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
2015-06-25 22:22:47

Wygląda na to, że te dwa pojęcia różnią się od siebie.

Bezpośrednie Odlewanie

Typy nie muszą być ściśle ze sobą powiązane. Występuje we wszystkich rodzajach smaków.
  • Custom implicit / explicit casting: zazwyczaj tworzony jest nowy obiekt.
  • Typ wartości Implicit: Kopiowanie bez utraty informacji.
  • Typ wartości Explicit: Kopia I Informacje mogą zostać utracone.
  • jest-relacja: zmiana referencji typ, w przeciwnym razie rzuca wyjątek.
  • ten sam typ: 'Casting jest zbędny'.
Wydaje się, że obiekt zostanie przekształcony w coś innego.

Jako operator

Typy mają bezpośredni związek. Jak w:

  • typy odniesienia: jest-relacja obiekty są zawsze takie same, tylko zmiany odniesienia.
  • typy wartości: Kopiuj boks i typy nullable.

It feels like The you are będzie obsługiwać obiekt w inny sposób.

Próbki i IL

    class TypeA
    {
        public int value;
    }

    class TypeB
    {
        public int number;

        public static explicit operator TypeB(TypeA v)
        {
            return new TypeB() { number = v.value };
        }
    }

    class TypeC : TypeB { }
    interface IFoo { }
    class TypeD : TypeA, IFoo { }

    void Run()
    {
        TypeA customTypeA = new TypeD() { value = 10 };
        long longValue = long.MaxValue;
        int intValue = int.MaxValue;

        // Casting 
        TypeB typeB = (TypeB)customTypeA; // custom explicit casting -- IL:  call class ConsoleApp1.Program/TypeB ConsoleApp1.Program/TypeB::op_Explicit(class ConsoleApp1.Program/TypeA)
        IFoo foo = (IFoo)customTypeA; // is-a reference -- IL: castclass  ConsoleApp1.Program/IFoo

        int loseValue = (int)longValue; // explicit -- IL: conv.i4
        long dontLose = intValue; // implict -- IL: conv.i8

        // AS 
        int? wraps = intValue as int?; // nullable wrapper -- IL:  call instance void valuetype [System.Runtime]System.Nullable`1<int32>::.ctor(!0)
        object o1 = intValue as object; // box -- IL: box [System.Runtime]System.Int32
        TypeD d1 = customTypeA as TypeD; // reference conversion -- IL: isinst ConsoleApp1.Program/TypeD
        IFoo f1 = customTypeA as IFoo; // reference conversion -- IL: isinst ConsoleApp1.Program/IFoo

        //TypeC d = customTypeA as TypeC; // wouldn't compile
    }
 3
Author: Lucas Teixeira,
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
2016-09-25 04:47:48

Chciałbym zwrócić uwagę na następujące cechy operatora As:

Https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/as

Zauważ, że operator as wykonuje tylko konwersje referencji, konwersje zerowe i konwersje bokserskie. Operator as nie może wykonywać inne konwersje, np. zdefiniowane przez użytkownika konwersje, które zamiast tego powinny być wykonywane za pomocą wyrażeń cast.

 2
Author: V. 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
2018-10-17 12:11:02

Gdy próbuję uzyskać reprezentację łańcuchową czegokolwiek (dowolnego typu), co potencjalnie może być null, preferuję poniższy wiersz kodu. Jest zwarta, wywołuje ToString () i poprawnie obsługuje null. Jeśli o jest null, s będzie zawierać ciąg znaków.Pusty.

String s = String.Concat(o);
 0
Author: xtrem,
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
2012-06-23 01:31:48

Ponieważ nikt o tym nie wspomniał, najbliżej instanceOf do Javy według słowa kluczowego jest to:

obj.GetType().IsInstanceOfType(otherObj)
 0
Author: Bennett Yeo,
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-10-13 20:21:25

Użyj direct cast string s = (string) o;, jeśli w logicznym kontekście aplikacji string jest jedynym prawidłowym typem. Dzięki temu podejściu uzyskasz InvalidCastException i zaimplementujesz zasadę Fail-fast. Twoja logika będzie chroniona przed przekazaniem nieprawidłowego typu dalej lub uzyskaniem NullReferenceException, jeśli zostanie użyty operator as.

Jeśli logika spodziewa się kilku różnych typów rzucać string s = o as string; i sprawdzić na null lub użyć operatora is.

W C# 7.0 pojawiła się nowa funkcja cool, aby uprościć obsadę i sprawdź to dopasowanie wzorca :

if(o is string s)
{
  // Use string variable s
}

or

switch (o)
{
  case int i:
     // Use int variable i
     break;
  case string s:
     // Use string variable s
     break;
 }
 0
Author: Dmitry,
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-03 07:34:30