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?
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.
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
-
string s = (string)o;
użyj, gdy coś powinno zdecydowanie być inną rzeczą. -
string s = o as string;
Użyj, gdy coś może być innym rzecz. -
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.
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.
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.
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
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.
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.
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.
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.
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).
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.
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'.
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
}
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.
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);
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)
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;
}
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