Warum sollte Gießen vermieden werden? [geschlossen]


97

Ich vermeide Casting-Typen im Allgemeinen so weit wie möglich, da ich den Eindruck habe, dass es sich um eine schlechte Codierungspraxis handelt und möglicherweise Leistungseinbußen auftreten.

Aber wenn mich jemand fragen würde, warum genau das so ist, würde ich sie wahrscheinlich wie ein Reh im Scheinwerferlicht ansehen.

Warum / wann ist Casting schlecht?

Ist es allgemein für Java, C #, C ++ oder behandelt jede andere Laufzeitumgebung es zu ihren eigenen Bedingungen?

Besonderheiten für eine beliebige Sprache sind willkommen. Beispiel: Warum ist es in C ++ schlecht?


3
Woher hast du diesen Eindruck?
Oded

8
Ich hatte diesen Eindruck, da ich noch nie ein Buch gelesen oder einen Programmierer getroffen habe, der sagte: "CASTING SOOOO GOOOOD !!!"
LoudNPossiblyWrong

15
Die Antwort für C ++ unterscheidet sich zwangsläufig von der Antwort für C #. Das ist sehr sprachspezifisch. Die bisherigen Antworten beantworten diese Frage für bestimmte Sprachen und geben in einigen Fällen nicht an, über welche Sprache sie sprechen.
James McNellis

2
Schlecht ist ein relativer Begriff. Das Vermeiden von Casting ist eine bewährte Methode, aber manchmal muss ein Programmierer das tun, was ein Programmierer tun muss. (Insbesondere, wenn Sie ein Java 1.5+ -Programm schreiben, das eine für 1.4 geschriebene Bibliothek verwendet.) Benennen Sie die Frage möglicherweise um: "Warum sollte Casting vermieden werden?"
Mike Miller

2
Dies ist eine großartige Frage ... Sie wurde von 5 Benutzern geschlossen, die jeweils weniger als 10.000 Ruf haben !! Ein übereifriger Einsatz neuer Kräfte, klar. Habe für die Wiedereröffnung gestimmt.
erreichen4thelasers

Antworten:


141

Sie haben dies mit drei Sprachen markiert, und die Antworten sind zwischen den drei wirklich sehr unterschiedlich. Die Diskussion über C ++ impliziert mehr oder weniger auch die Diskussion über C-Casts, und das gibt (mehr oder weniger) eine vierte Antwort.

Da es das ist, was Sie nicht explizit erwähnt haben, beginne ich mit C. C-Casts haben eine Reihe von Problemen. Zum einen können sie verschiedene Dinge tun. In einigen Fällen sagt die Besetzung lediglich dem Compiler (im Wesentlichen): "Halt die Klappe, ich weiß, was ich tue" - dh sie stellt sicher, dass der Compiler auch bei einer Konvertierung Probleme verursacht Ich werde Sie nicht vor diesen möglichen Problemen warnen. Nur zum Beispiel char a=(char)123456;. Das genaue Ergebnis dieser Implementierung wird definiert (hängt von der Größe und Signatur von abchar), und außer in ziemlich seltsamen Situationen, ist wahrscheinlich nicht nützlich. C-Casts unterscheiden sich auch darin, ob sie nur zur Kompilierungszeit (dh Sie sagen dem Compiler nur, wie einige Daten interpretiert / behandelt werden sollen) oder zur Laufzeit (z. B. eine tatsächliche Konvertierung von double in) erfolgen lange).

C ++ versucht, dies zumindest teilweise zu bewältigen, indem eine Reihe von "neuen" Cast-Operatoren hinzugefügt werden, von denen jeder nur auf eine Teilmenge der Funktionen eines C-Cast beschränkt ist. Dies macht es schwieriger, (zum Beispiel) versehentlich eine Konvertierung durchzuführen, die Sie wirklich nicht beabsichtigt haben. Wenn Sie nur beabsichtigen, die Konstanz eines Objekts zu beseitigen, können Sie sie verwenden const_castund sicherstellen, dass das einzige, was davon betroffen sein kann, ob ein Objekt ist const, volatileoder nicht. Umgekehrt static_castdarf a nicht beeinflussen, ob ein Objekt ist constoder nichtvolatile. Kurz gesagt, Sie haben die meisten der gleichen Arten von Funktionen, aber sie sind kategorisiert, sodass eine Besetzung im Allgemeinen nur eine Art von Konvertierung durchführen kann, während eine einzelne Besetzung im C-Stil zwei oder drei Konvertierungen in einem Vorgang ausführen kann. Die primäre Ausnahme ist , dass Sie kann ein verwenden dynamic_castanstelle von einer static_castzumindest in einigen Fällen und obwohl sie geschrieben als dynamic_cast, es wird wirklich als ein Ende static_cast. Zum Beispiel können Sie dynamic_casteine Klassenhierarchie nach oben oder unten durchlaufen - aber ein Cast "up" der Hierarchie ist immer sicher, so dass dies statisch erfolgen kann, während ein Cast "down" die Hierarchie nicht unbedingt sicher ist, so ist es dynamisch gemacht.

Java und C # sind einander viel ähnlicher. Insbesondere bei beiden ist das Gießen (praktisch?) Immer eine Laufzeitoperation. In Bezug auf die C ++ - Cast-Operatoren ist es dynamic_castin Bezug auf das, was wirklich getan wird , normalerweise am nächsten an a. Wenn Sie also versuchen, ein Objekt in einen Zieltyp umzuwandeln, fügt der Compiler eine Laufzeitprüfung ein, um festzustellen, ob diese Konvertierung zulässig ist und eine Ausnahme auslösen, wenn dies nicht der Fall ist. Die genauen Details (z. B. der Name, der für die Ausnahme "Bad Cast" verwendet wird) variieren, aber das Grundprinzip bleibt größtenteils ähnlich (obwohl Java, wenn Speicher dient, Casts auf die wenigen Nicht-Objekttypen anwendet, die intviel näher an C liegen Casts - aber diese Typen werden selten genug verwendet, dass 1) ich mich nicht sicher daran erinnere und 2) selbst wenn es wahr ist, es sowieso nicht viel ausmacht).

Wenn man die Dinge allgemeiner betrachtet, ist die Situation ziemlich einfach (zumindest IMO): Eine Besetzung (offensichtlich genug) bedeutet, dass Sie etwas von einem Typ in einen anderen konvertieren. Wann / wenn Sie das tun, wirft es die Frage "Warum?" Wenn Sie wirklich möchten, dass etwas ein bestimmter Typ ist, warum haben Sie es nicht zunächst als diesen Typ definiert? Das heißt nicht, dass es nie einen Grund gibt, eine solche Konvertierung durchzuführen, aber jedes Mal, wenn dies geschieht, sollte sich die Frage stellen, ob Sie den Code neu entwerfen können, sodass durchgehend der richtige Typ verwendet wurde. Selbst scheinbar harmlose Konvertierungen (z. B. zwischen Ganzzahl und Gleitkomma) sollten viel genauer als üblich untersucht werden. Trotz ihres AnscheinesÄhnlichkeit, Ganzzahlen sollten wirklich für "gezählte" Arten von Dingen und Gleitkomma für "gemessene" Arten von Dingen verwendet werden. Das Ignorieren der Unterscheidung führt zu einigen verrückten Aussagen wie "Die durchschnittliche amerikanische Familie hat 1,8 Kinder". Obwohl wir alle sehen können, wie das passiert, ist die Tatsache, dass keine Familie 1,8 Kinder hat. Sie könnten 1 oder sie könnten 2 haben oder sie könnten mehr als das haben - aber niemals 1.8.


10
Sieht so aus, als ob Sie hier unter "Tod durch Aufmerksamkeitsspanne" leiden. Dies ist eine nette Antwort imo.
Steve Townsend

2
Eine starke Antwort, aber einige der Teile "Ich weiß nicht" könnten verschärft werden, um sie umfassend zu gestalten. @ Dragontamer5788 es ist eine gute Antwort, aber nicht umfassend.
M2tM

5
Ein ganzes Kind und ein Kind mit einem fehlenden Bein wären 1,8 Kinder. Aber trotzdem eine sehr schöne Antwort. :)
Oz.

1
Eine sehr schöne Antwort, die nicht im geringsten durch den Ausschluss von Paaren ohne Kinder behindert wird .

@ Roger: nicht ausschließen, nur ignorieren.
Jerry Coffin

48

Viele gute Antworten hier. So sehe ich das (aus C # -Perspektive).

Casting bedeutet normalerweise eines von zwei Dingen:

  • Ich kenne den Laufzeittyp dieses Ausdrucks, aber der Compiler kennt ihn nicht. Compiler, ich sage Ihnen, zur Laufzeit wird das Objekt, das diesem Ausdruck entspricht, wirklich von diesem Typ sein. Ab sofort wissen Sie, dass dieser Ausdruck als von diesem Typ zu behandeln ist. Generieren Sie Code, der davon ausgeht, dass das Objekt vom angegebenen Typ ist, oder lösen Sie eine Ausnahme aus, wenn ich falsch liege.

  • Sowohl der Compiler als auch der Entwickler kennen den Laufzeittyp des Ausdrucks. Dem Wert, den dieser Ausdruck zur Laufzeit hat, ist ein anderer Wert eines anderen Typs zugeordnet. Generieren Sie Code, der den Wert des gewünschten Typs aus dem Wert des angegebenen Typs erzeugt. Wenn Sie dies nicht tun können, lösen Sie eine Ausnahme aus.

Beachten Sie, dass dies Gegensätze sind . Es gibt zwei Arten von Abgüssen! Es gibt Casts, in denen Sie dem Compiler einen Hinweis auf die Realität geben - hey, dieses Typobjekt ist tatsächlich vom Typ Customer - und es gibt Casts, in denen Sie den Compiler anweisen, eine Zuordnung von einem Typ zu einem anderen durchzuführen - hey, Ich brauche das int, das diesem Double entspricht.

Beide Arten von Abgüssen sind rote Fahnen. Die erste Art der Besetzung wirft die Frage auf: "Warum genau weiß der Entwickler etwas, was der Compiler nicht weiß?" Wenn Sie sich in einer solchen Situation befinden, ist es normalerweise besser, das Programm so zu ändern, dass der Compiler die Realität im Griff hat. Dann brauchst du die Besetzung nicht; Die Analyse erfolgt zur Kompilierungszeit.

Die zweite Art der Besetzung wirft die Frage auf: "Warum wird die Operation nicht überhaupt im Zieldatentyp ausgeführt?" Wenn Sie ein Ergebnis in Ints benötigen, warum halten Sie dann überhaupt ein Double? Solltest du nicht einen Int halten?

Einige zusätzliche Gedanken hier:

http://blogs.msdn.com/b/ericlippert/archive/tags/cast+operator/


2
Ich denke nicht, dass dies von Natur aus rote Fahnen sind. Wenn Sie ein FooObjekt haben, von dem erbt Bar, und das Sie in einem speichern, List<Bar>benötigen Sie Casts, wenn Sie das Foozurückhaben möchten . Vielleicht weist es auf ein Problem auf architektonischer Ebene hin (warum speichern wir Bars anstelle von Foos?), Aber nicht unbedingt. Und wenn das Fooauch eine gültige Besetzung hat, intgeht es auch um Ihren anderen Kommentar: Sie speichern ein Foo, kein int, weil ein intnicht immer angemessen ist.
Mike Caron

6
@ Mike Caron - Ich kann natürlich nicht für Eric antworten, aber für mich bedeutet eine rote Fahne "das ist etwas, worüber man nachdenken muss", nicht "das ist etwas falsch". Und es gibt keine Probleme beim Speichern eines Fooin einem List<Bar>, aber an der Stelle der Besetzung, an der Sie versuchen, etwas zu tun, Foodas für ein nicht geeignet ist Bar. Das bedeutet, dass ein unterschiedliches Verhalten für Subtypen durch einen anderen Mechanismus als den eingebauten Polymorphismus erzielt wird, der durch virtuelle Methoden bereitgestellt wird. Vielleicht ist das die richtige Lösung, aber häufiger ist es eine rote Fahne.
Jeffrey L Whitledge

13
Tatsächlich. Wenn Sie Dinge aus einer Liste von Tieren herausziehen und später dem Compiler mitteilen müssen, ach übrigens, ich weiß zufällig, dass der erste ein Tiger ist, der zweite ein Löwe und der dritte ist ein Bär, dann hätten Sie ein Tupel <Löwe, Tiger, Bär> verwenden sollen, keine Liste <Tier>.
Eric Lippert

5
Ich stimme Ihnen zu, aber ich denke, dass ohne eine bessere syntaktische Unterstützung für Tuple<X,Y,...>Tupel eine breite Verwendung in C # unwahrscheinlich ist. Dies ist ein Ort, an dem die Sprache die Menschen besser in die "Grube des Erfolgs" treiben könnte.
KVB

4
@kvb: Ich stimme zu. Wir haben überlegt, eine Tupel-Syntax für C # 4 zu verwenden, die jedoch nicht in das Budget passt. Vielleicht in C # 5; Wir haben noch nicht alle Funktionen ausgearbeitet. Zu beschäftigt damit, das CTP für die Asynchronisation zusammenzubringen. Oder vielleicht in einer hypothetischen zukünftigen Version.
Eric Lippert

36

Casting-Fehler werden in Java immer als Laufzeitfehler gemeldet. Durch die Verwendung von Generika oder Vorlagen werden diese Fehler in Fehler zur Kompilierungszeit umgewandelt, sodass Sie leichter erkennen können, wenn Sie einen Fehler gemacht haben.

Wie ich oben sagte. Das soll nicht heißen, dass alles Casting schlecht ist. Aber wenn es möglich ist, es zu vermeiden, ist es am besten, dies zu tun.


4
Dies setzt voraus, dass alle Castings "schlecht" sind; Dies ist jedoch nicht ganz richtig. Nehmen wir zum Beispiel C # mit impliziter und expliziter Cast-Unterstützung. Das Problem tritt auf, wenn eine Besetzung durchgeführt wird, bei der (versehentlich) Informationen oder Typensicherheit entfernt werden (dies unterscheidet sich je nach Sprache).

5
Tatsächlich ist dies in C ++ völlig falsch. Möglicherweise ist eine Bearbeitung angebracht, um die Sprache (n) aufzunehmen, auf die diese Informationen abzielen.
Steve Townsend

@Erick - Ich würde, aber ich weiß weder das Erste über Java noch genug C # -Details, um sicherzugehen, dass die Informationen korrekt sind.
Steve Townsend

Entschuldigung, ich bin ein Java-Typ, daher sind meine C ++ - Kenntnisse begrenzt genug. Ich konnte das Wort "Templating" daraus herausarbeiten, da es vage sein sollte.
Mike Miller

Nicht so. Einige Cast-Fehler werden vom Java-Compiler abgefangen, nicht nur generische. Betrachten Sie (String) 0;
Marquis von Lorne

18

Casting ist nicht von Natur aus schlecht, es ist nur so, dass es oft als Mittel missbraucht wird, um etwas zu erreichen, das entweder gar nicht oder eleganter gemacht werden sollte.

Wenn es allgemein schlecht wäre, würden Sprachen es nicht unterstützen. Wie jedes andere Sprachmerkmal hat es seinen Platz.

Mein Rat wäre, sich auf Ihre Primärsprache zu konzentrieren und alle Darsteller und die damit verbundenen Best Practices zu verstehen. Das sollte Ausflüge in andere Sprachen informieren.

Die relevanten C # -Dokumente finden Sie hier .

Bei einer früheren SO-Frage finden Sie hier eine großartige Zusammenfassung der C ++ - Optionen .


9

Ich spreche hier hauptsächlich für C ++ , aber das meiste davon gilt wahrscheinlich auch für Java und C #:

C ++ ist eine statisch typisierte Sprache . Es gibt einige Spielräume, die die Sprache Ihnen dabei erlaubt (virtuelle Funktionen, implizite Konvertierungen), aber im Grunde kennt der Compiler den Typ jedes Objekts zur Kompilierungszeit. Der Grund für die Verwendung einer solchen Sprache besteht darin, dass beim Kompilieren Fehler auftreten können . Wenn der Compiler die Typen kennen aund bdann wird es Ihnen zur Compile-Zeit zu fangen , wenn Sie das tun , a=bwo aeine komplexe Zahl ist und bist eine Zeichenfolge.

Wann immer Sie explizites Casting durchführen, weisen Sie den Compiler an, den Mund zu halten, weil Sie glauben , es besser zu wissen . Falls Sie sich irren, werden Sie dies normalerweise erst zur Laufzeit herausfinden . Und das Problem beim Herausfinden zur Laufzeit ist, dass dies möglicherweise bei einem Kunden liegt.


5

Java, c # und c ++ sind stark typisierte Sprachen. Obwohl stark typisierte Sprachen als unflexibel angesehen werden können, haben sie den Vorteil, dass sie zur Kompilierungszeit eine Typprüfung durchführen und Sie vor Laufzeitfehlern schützen, die durch den falschen Typ für bestimmte Vorgänge verursacht werden.

Grundsätzlich gibt es zwei Arten von Besetzungen: eine Besetzung für einen allgemeineren Typ oder eine Besetzung für einen anderen Typ (spezifischer). Beim Umwandeln in einen allgemeineren Typ (Umwandeln in einen übergeordneten Typ) bleiben die Überprüfungen der Kompilierungszeit erhalten. Das Casting in andere Typen (spezifischere Typen) deaktiviert jedoch die Überprüfung des Typs zur Kompilierungszeit und wird vom Compiler durch eine Laufzeitprüfung ersetzt. Dies bedeutet, dass Sie weniger sicher sind, dass der kompilierte Code korrekt ausgeführt wird. Aufgrund der zusätzlichen Laufzeit-Typprüfung (die Java-API ist voll von Casts!) Hat dies auch einige vernachlässigbare Auswirkungen auf die Leistung.


5
Nicht alle Casts "Bypass" -Sicherheit in C ++.
James McNellis

4
Nicht alle Casts "Bypass" -Sicherheit in C #.

5
Nicht alle Casts "Bypass" -Sicherheit in Java.
Erick Robertson

11
Nicht alle Güsse "Bypass" -Sicherheit beim Gießen. Oh warte, dieses Tag bezieht sich nicht auf eine Sprache ...
sbi

2
In fast allen Fällen in C # und Java führt das Casting zu Leistungseinbußen, da das System eine Laufzeit-Typprüfung durchführt (die nicht kostenlos ist). In C ++ dynamic_castist es im Allgemeinen langsamer als static_cast, da es im Allgemeinen eine Laufzeitüberprüfung des Typs durchführen muss (mit einigen Einschränkungen: Das Umwandeln in einen Basistyp ist billig usw.).
Travis Gockel

4

Einige Gussarten sind so sicher und effizient, dass sie oft gar nicht als Guss betrachtet werden.

Wenn Sie von einem abgeleiteten Typ in einen Basistyp umwandeln, ist dies im Allgemeinen recht billig (häufig - abhängig von Sprache, Implementierung und anderen Faktoren - kostengünstig) und sicher.

Wenn Sie von einem einfachen Typ wie einem Int zu einem breiteren Typ wie einem Long Int umwandeln, ist dies wiederum oft recht billig (im Allgemeinen nicht viel teurer als das Zuweisen des gleichen Typs, dem dieser Cast zugewiesen wurde) und wiederum sicher.

Andere Typen sind voller und / oder teurer. In den meisten Sprachen ist das Umwandeln von einem Basistyp in einen abgeleiteten Typ entweder billig, birgt jedoch ein hohes Risiko schwerwiegender Fehler (in C ++ ist es billig, wenn Sie static_cast von Basis zu abgeleitet ableiten, aber wenn der zugrunde liegende Wert nicht vom abgeleiteten Typ ist, ist der Verhalten ist undefiniert und kann sehr seltsam sein) oder relativ teuer und mit dem Risiko, eine Ausnahme auszulösen (dynamic_cast in C ++, explizite Basis-zu-Ableitung-Umwandlung in C # usw.). Das Boxen in Java und C # ist ein weiteres Beispiel dafür und ein noch größerer Aufwand (wenn man bedenkt, dass sie sich mehr ändern als nur, wie die zugrunde liegenden Werte behandelt werden).

Andere Arten von Cast können Informationen verlieren (ein langer Integer-Typ zu einem kurzen Integer-Typ).

Diese Fälle von Risiko (ob Ausnahme oder schwerwiegenderer Fehler) und Kosten sind alles Gründe, um das Gießen zu vermeiden.

Ein konzeptionellerer, aber vielleicht wichtigerer Grund ist, dass jeder Fall des Castings ein Fall ist, in dem Ihre Fähigkeit, über die Richtigkeit Ihres Codes nachzudenken, beeinträchtigt wird: Jeder Fall ist ein anderer Ort, an dem etwas schief gehen kann und wie es funktioniert kann schief gehen und die Komplexität der Ableitung erhöhen, ob das gesamte System schief geht. Selbst wenn die Besetzung jedes Mal nachweislich sicher ist, ist der Beweis, dass dies ein zusätzlicher Teil der Argumentation ist.

Schließlich kann die häufige Verwendung von Casts darauf hinweisen, dass das Objektmodell entweder beim Erstellen, bei der Verwendung oder bei beiden nicht gut berücksichtigt wurde: Das häufige Hin- und Herwechseln zwischen denselben wenigen Typen führt fast immer dazu, dass die Beziehungen zwischen den Typen nicht berücksichtigt werden gebraucht. Hier sind Casts nicht so sehr schlecht, sondern ein Zeichen für etwas Schlechtes.


2

Es gibt eine wachsende Tendenz für Programmierer, sich an dogmatische Regeln für die Verwendung von Sprachfunktionen zu halten ("niemals XXX verwenden!", "XXX als schädlich angesehen" usw.), wobei XXX von gotos über Zeiger zu protectedDatenelementen zu Singletons zu vorbeigehenden Objekten reicht Wert.

Das Befolgen solcher Regeln stellt meiner Erfahrung nach zwei Dinge sicher: Sie werden weder ein schrecklicher Programmierer sein, noch werden Sie ein großartiger Programmierer sein.

Ein viel besserer Ansatz ist es , zu graben und aufzudecken den Kern der Wahrheit hinter dieser Decke Verboten und dann die Eigenschaften umsichtig, mit dem Verständnis , dass es gibt viele Situationen , in denen sie das beste Werkzeug für den Job sind.

"Ich vermeide Casting-Typen im Allgemeinen so weit wie möglich" ist ein gutes Beispiel für eine solche übergeneralisierte Regel. Abgüsse sind in vielen häufigen Situationen unerlässlich. Einige Beispiele:

  1. Bei der Interaktion mit Code von Drittanbietern (insbesondere wenn dieser Code voller typedefs ist). (Beispiel: GLfloat<--> double<--> Real.)
  2. Casting von einem abgeleiteten Zeiger auf eine Basisklasse / Referenz: Dies ist so häufig und natürlich, dass der Compiler dies implizit tut. Wenn eine explizite Darstellung die Lesbarkeit erhöht, ist die Besetzung ein Schritt vorwärts und nicht rückwärts!
  3. Umwandlung von einer Basis in einen abgeleiteten Klassenzeiger / eine abgeleitete Referenz: Auch in gut gestaltetem Code üblich. (Beispiel: heterogene Behälter.)
  4. Innerhalb der binären Serialisierung / Deserialisierung oder anderen Low-Level-Codes, die Zugriff auf die Rohbytes der integrierten Typen benötigen.
  5. Jederzeit, wenn es einfach natürlicher, bequemer und lesbarer ist, einen anderen Typ zu verwenden. (Beispiel: std::size_type-> int.)

Es gibt sicherlich viele Situationen, in denen es nicht angebracht ist, eine Besetzung zu verwenden, und es ist wichtig, diese auch zu lernen. Ich werde nicht zu sehr ins Detail gehen, da die obigen Antworten gute Arbeit geleistet haben und einige davon hervorgehoben haben.


1

Um auf die Antwort von KDeveloper einzugehen , ist sie nicht von Natur aus typsicher. Beim Casting gibt es keine Garantie dafür, dass das, von dem Sie gießen und zu dem Sie gießen, übereinstimmt. In diesem Fall erhalten Sie eine Laufzeitausnahme, was immer eine schlechte Sache ist.

In Bezug auf C # haben Sie die Möglichkeit, (größtenteils) zu entscheiden, ob eine Besetzung erfolgreich sein würde oder nicht , da sie die Operatoren isund enthält as. Aus diesem Grund sollten Sie die entsprechenden Schritte ausführen, um festzustellen, ob der Vorgang erfolgreich ist, und entsprechend vorgehen.


1

Im Fall von C # muss man beim Casting vorsichtiger sein, da beim Umgang mit Werttypen Overheads beim Boxen / Unboxen anfallen.


1

Ich bin mir nicht sicher, ob jemand dies bereits erwähnt hat, aber in C # kann Casting auf ziemlich sichere Weise verwendet werden und ist oft notwendig. Angenommen, Sie erhalten ein Objekt, das von verschiedenen Typen sein kann. Mit dem isSchlüsselwort können Sie zunächst bestätigen, dass das Objekt tatsächlich von dem Typ ist, in den Sie es umwandeln möchten, und dann das Objekt direkt in diesen Typ umwandeln. (Ich habe nicht viel mit Java gearbeitet, aber ich bin mir sicher, dass es auch dort eine sehr einfache Möglichkeit gibt).


1

Sie wandeln ein Objekt nur dann in einen Typ um, wenn zwei Bedingungen erfüllt sind:

  1. Sie wissen, dass es von diesem Typ ist
  2. Der Compiler tut dies nicht

Dies bedeutet, dass nicht alle Informationen, die Sie haben, in der von Ihnen verwendeten Typstruktur gut dargestellt sind. Dies ist schlecht, da Ihre Implementierung Ihr Modell semantisch umfassen sollte , was in diesem Fall eindeutig nicht der Fall ist.

Wenn Sie eine Besetzung machen, kann dies zwei verschiedene Gründe haben:

  1. Sie haben die Typbeziehungen schlecht ausgedrückt.
  2. Das Sprachtypsystem ist einfach nicht ausdrucksstark genug, um sie zu formulieren.

In den meisten Sprachen stößt man häufig auf die 2. Situation. Generika wie in Java helfen ein bisschen, das C ++ - Vorlagensystem noch mehr, aber es ist schwer zu beherrschen und selbst dann können einige Dinge unmöglich oder einfach nicht die Mühe wert sein.

Man könnte also sagen, eine Besetzung ist ein schmutziger Hack, um Ihre Probleme zu umgehen und eine bestimmte Typbeziehung in einer bestimmten Sprache auszudrücken. Schmutzige Hacks sollten vermieden werden. Aber ohne sie kann man nie leben.


0

Im Allgemeinen sind Vorlagen (oder Generika) typsicherer als Casts. In dieser Hinsicht würde ich sagen, dass ein Problem beim Gießen die Typensicherheit ist. Es gibt jedoch ein anderes subtileres Problem, das insbesondere mit Downcasting verbunden ist: Design. Zumindest aus meiner Sicht ist Downcasting ein Code-Geruch, ein Hinweis darauf, dass etwas mit meinem Design nicht stimmt, und ich sollte weiter nachforschen. Warum ist einfach: Wenn Sie die Abstraktionen richtig "verstehen", brauchen Sie sie einfach nicht! Schöne Frage übrigens ...

Prost!


0

Um es kurz zu machen, ein guter Grund ist die Portabilität. Unterschiedliche Architekturen, die beide dieselbe Sprache unterstützen, können beispielsweise unterschiedlich große Ints haben. Wenn ich also von ArchA zu ArchB migriere, das einen engeren int hat, sehe ich möglicherweise bestenfalls ein merkwürdiges Verhalten und im schlimmsten Fall einen Seg-Fehler.

(Ich ignoriere eindeutig architekturunabhängigen Bytecode und IL.)

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.