C# Wie gebe ich einen Status Code in einem MVC Controller mit spezifischem Typ zurück?

Kokujou

Lieutenant
Registriert
Dez. 2017
Beiträge
948
Hallo ihr Lieben,

Bei einem C# Controller hat man ja 3 Möglichkeiten. Entweder man gibt IActionResult zurück, oder ein typisidertes ActionResult<T> oder direkt den spezifischen Typ T
Ich benutze aktuell ActionResult<T>, aber ich merke dass es völlig egal ist was man als T im generischen Parameter angibt, der Compiler erkennt nur wenn du etwas zurück gibst dass kein Status Resultat ist.

Ich würde das gerne etwas strenger typen, das Problem ist nur: Wenn ich den spezifischen Typ T angebe kann ich nicht mehr sagen welchen StatusCode ich zurückgeben möchte.

Sicherlich würde eine Exception in einen negativen Status Code umgwandelt, vielleicht 400 - schlimmstenfalls 500.
Aber ich möchte ja auch gerne mal NoContent, Forbid, Unauthorized oder NotFound zurückgeben.

gibt es irgendeinen weg das bei einem Endpunkt mit spezifischem Rückgabetyp zu tun?
 
nicht wirklich, denn die Frage bleibt, wie gebe ich einen statuscode zurück während der Endpunkt keinen ActionResult return type hat?
 
also so ähnlich wie hier?

public Product GetProduct(int id) { Product item = repository.Get(id); if (item == null) { var resp = new HttpResponseMessage(HttpStatusCode.NotFound) { Content = new StringContent(string.Format("No product with ID = {0}", id)), ReasonPhrase = "Product ID Not Found" }; throw new HttpResponseException(resp); } return item; }
 
Mal zurück auf Anfang.
Was willst du denn zurückgeben außer 200 Ok mit inhalt als z.B. Json oder soetwas wie 4XX ?
 
Kalsarikännit schrieb:
also so ähnlich wie hier?

public Product GetProduct(int id) { Product item = repository.Get(id); if (item == null) { var resp = new HttpResponseMessage(HttpStatusCode.NotFound) { Content = new StringContent(string.Format("No product with ID = {0}", id)), ReasonPhrase = "Product ID Not Found" }; throw new HttpResponseException(resp); } return item; }
ja genau. es wäre schön wen ich in der exception sowas wie ein notfound oder so zurückgeben könnte...
also wenns was gäbe wie throw new 404NotFoundException oder 401UnauthorizedException die in dem Zusammenhang in eine status response übersetzt würde
 
middleware seh ich immer son bischen wie hacking... Betonung auf "Bischen".
gibt es denn da nichts out of the box?
oder ist es tatsächlich so ungewöhnlich dass man gerne differenzieren möchte? ich meine es gibt allein an positiven Status Codes fast ein dutzend. Ok, NoContent, Content und und und.

mich würde interessieren was da für eine Idee dahinter steckt, wie sieht denn die Konvention aus, wenn man dem Endpunkt einen exakten Return Type gibt? dabei hat sich doch sicher jemand was gedacht.
 
Hast du mal getestet was passiert wenn du das IActionResult typisierst und dann einen anderen Typ zurückgibst? Könnte mir vorstellen, dass dann der Serializer meckert zur Laufzeit.

Dir ging’s ja wenn ich das richtig verstanden habe um die Konvention zur Compilezeit.

Ohne groß was zu Implementieren, fällt mir da auf die Schnelle auch nix ein. Außer vielleicht noch Unit-/E2E/Integrationstets die sicherstellen, das die Typen da in jedem Fall matchen. Und für die Konsumenten eine Swagger Doku versteht sich.
 
ja darum bin ich auch überrascht dass das typisierte ActionResult nicht meckert wenn man dann einen anderen Typ zurück gibt... das ist wirklich sehr eigenartig, wozu typiiert man es dann überhaupt? Programme wie NSwag und Swagger kriegen es natürlich mit und generieren entsprechend dokumentation, was mir schonmal sehr weiterhilft.

Ich werd wohl um die MiddleWare nicht drumrum kommen wenn ich die Type Safety erhöhen will, aber ich hatte ehrllich gesagt gehofft dass ichmal wieder einfach nur zu blöd bin und das offensichtlichste übersehen habe >.<
 
Die Typisierung funktioniert - und du kannst auch nicht jeden beliebigen Typen zurückgeben, sondern maximal einen beliebigen Typen, der in einem ActionResult gekapselt ist. Dass das funktioniert liegt den implicit operators, die ein ActionResult<T> implementiert.

[HttpGet] public ActionResult<Auto> Get() { return this.Ok(new Auto()); // Ok() liefert ein OkObjectResult : ObjectResult : ActionResult }

Der hier greifende implicit operator sieht folgendermaßen aus:

/// <summary> /// Implictly converts the specified <paramref name="result"/> to an <see cref="ActionResult{TValue}"/>. /// </summary> /// <param name="result">The <see cref="ActionResult"/>.</param> public static implicit operator ActionResult<TValue>(ActionResult result) { return new ActionResult<TValue>(result); }

Wenn du aber statt ein Auto ein Flugzeug zurückgibst, dann bekommst du einen Type Error, sprich:

[HttpGet] public ActionResult<Auto> Get() { return new Flugzeug(); // Fehler! }

Warum? Weil hier dann der andere implicit operator greift, dessen Argument dann aber nicht mehr mit deinem gesetzen Generic übereinstimmt:

/// <summary> /// Implictly converts the specified <paramref name="value"/> to an <see cref="ActionResult{TValue}"/>. /// </summary> /// <param name="value">The value to convert.</param> public static implicit operator ActionResult<TValue>(TValue value) // TValue ist in diesem Beispiel vom Typ Auto { return new ActionResult<TValue>(value); }
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: Dalek
Kokujou schrieb:
Ich werd wohl um die MiddleWare nicht drumrum kommen wenn ich die Type Safety erhöhen will
Aus meiner Sicht erhöhst du die Type Safety so nicht, sondern schränkst sie ein... in deiner Response kann eben nicht nur ein Product enthalten sein, sondern auch ein Fehler. Und wenn du den den return type nun auf Product beschränkst, erzählst du dem Compiler im Prinzip, dass kein Fehler passieren kann und IMMER ein Product zurück kommt.

Ein paar Aspekte, die ich beachten würde. Du solltest:
  • in jedem Fall ein ActionResult oder IActionResult verwenden, wenn du mehrere Ergebnistypen hast
  • mit Attributen beschreiben, was deine Methode zurück geben kann (ProducesResponseType...)
  • mit async Task arbeiten, um die potenzielle Verarbeitungsgeschwindigkeit zu erhöhen
  • mit den static imports arbeiten (Ok(), BadRequest(), etc.) um die Antworten zurück zu geben

Wie im Beispiel:

C#:
[HttpPost]
[Consumes(MediaTypeNames.Application.Json)]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<Product>> CreateAsync(Product product)
{
    if (product.Description.Contains("XYZ Widget"))
    {
        return BadRequest();
    }

    await _repository.AddProductAsync(product);

    return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}

Der Rückgabetyp einer ControllerAction ist für dich ohnehin nur bedingt interessant, da du diese Methode ja (vermutlich) nie manuell irgendwo aufrufst. Und mit deiner Vorgehensweise hast du jede Menge Nachteile, die die Vorteile einfach nicht aufwiegen können.

Was du noch ausprobieren kannst, um innerhalb der Controller mehr Typsicherheit bei Fehlern zu haben, ist die library https://github.com/gnaeus/OperationResult zu verwenden und mit doppelten / typisierten Rückgaben zu arbeiten (Rust-Style error handling). Du gibst bei einer Methode immer den Erfolgsfall und den Fehlerfall an und kannst sehr elegant prüfen, was davon eingetreten ist, ohne mit Exceptions hantieren zu müssen. Das ist etwas performanter und aus meiner Sicht auch eleganter. Ich setze diese library in meinen privaten Projekten schon seit einiger Zeit sehr erfolgreich ein.

C#:
using OperationResult;
using static OperationResult.Helpers;

public Result<double, string> SqrtOperation(double argument)
{
    if (argument < 0)
    {
        return Error("Argument must be greater than zero");
    }
    double result = Math.Sqrt(argument);
    return Ok(result);
}

public void Method()
{
    var result = SqrtOperation(123);
    if (result)
    {
        Console.WriteLine("Value is: {0}", result.Value);
    }
    else
    {
        Console.WriteLine("Error is: {0}", result.Error);
    }
}
 
VD90 schrieb:
Die Typisierung funktioniert - und du kannst auch nicht jeden beliebigen Typen zurückgeben, sondern maximal einen beliebigen Typen, der in einem ActionResult gekapselt ist. Dass das funktioniert liegt den implicit operators, die ein ActionResult<T> implementiert.

[HttpGet] public ActionResult<Auto> Get() { return this.Ok(new Auto()); // Ok() liefert ein OkObjectResult : ObjectResult : ActionResult }

Der hier greifende implicit operator sieht folgendermaßen aus:

/// <summary> /// Implictly converts the specified <paramref name="result"/> to an <see cref="ActionResult{TValue}"/>. /// </summary> /// <param name="result">The <see cref="ActionResult"/>.</param> public static implicit operator ActionResult<TValue>(ActionResult result) { return new ActionResult<TValue>(result); }

Wenn du aber statt ein Auto ein Flugzeug zurückgibst, dann bekommst du einen Type Error, sprich:

[HttpGet] public ActionResult<Auto> Get() { return new Flugzeug(); // Fehler! }

Warum? Weil hier dann der andere implicit operator greift, dessen Argument dann aber nicht mehr mit deinem gesetzen Generic übereinstimmt:

/// <summary> /// Implictly converts the specified <paramref name="value"/> to an <see cref="ActionResult{TValue}"/>. /// </summary> /// <param name="value">The value to convert.</param> public static implicit operator ActionResult<TValue>(TValue value) // TValue ist in diesem Beispiel vom Typ Auto { return new ActionResult<TValue>(value); }
mag sein aber das kümmert den compiler leider nicht sonderlich. Was wichtig ist ist dass der Build fehlschlägt wenn ich ein falsches Objekt zurückgebe, wenn es zur Laufzeit fehlschlägt ist das einfach zu spät, denn das führt ja zu bugs

sandreas schrieb:
mit den static imports arbeiten (Ok(), BadRequest(), etc.) um die Antworten zurück zu geben
den kannte ich noch nicht, seit wann brauche ich static imports für Status returns?
sandreas schrieb:
Aus meiner Sicht erhöhst du die Type Safety so nicht, sondern schränkst sie ein... in deiner Response kann eben nicht nur ein Product enthalten sein, sondern auch ein Fehler. Und wenn du den den return type nun auf Product beschränkst, erzählst du dem Compiler im Prinzip, dass kein Fehler passieren kann und IMMER ein Product zurück kommt.
wenn du sie als return type siehst, ja. aber ein error ist kein return type sondern eine exception. Eine Funktion kann immer zweierlei zurück geben, den eigentlichen return Wert und eine Exception. Die Exception kann dabei fast jedes beliebige Objekt sein solange es von Exception erbt.

Behandelte Status Codes wären z.B. 404 Object not found, 400 Invalid Input, 401 Unauthorized, 403 Forbidde, ...

Unbehandelte Codes wären hingegen sowas wie SQL exceptions, timeouts, tatsächliche Bugs, ...

beide über den haufen zu wärfen wäre... problematisch
sandreas schrieb:
Der Rückgabetyp einer ControllerAction ist für dich ohnehin nur bedingt interessant, da du diese Methode ja (vermutlich) nie manuell irgendwo aufrufst. Und mit deiner Vorgehensweise hast du jede Menge Nachteile, die die Vorteile einfach nicht aufwiegen können.
Es geht wirklich nur um den Compiler, er soll mir anzeigen wenn ich z.B. den Rückgabetyp eines Data Repositories geändert habe und ich deswegen das ActionResult ändern muss. Ich benutze NSWag clients die aus der API Dokumentaiton Typescript und C# clients generieren können. Wenn also der Typ des ActionResult nicht mit dem tatsächlichen Rückgabetyp übereinstimmt heißt es BUMM - bug.
 
Ich glaube du hast nicht verstanden, was ich geschrieben habe. Warum sollte es den Compiler denn jucken, wenn doch alles richtig ist?

@sandreas hat mit seinem Post völlig recht - dein Plan geht imo am guten Design einer API vorbei.

Für Ok() usw brauchst du auch keine static imports. Wenn dein Controller von „ControllerBase“ erbt, kannst du auf jeden erdenklichen StatusCode zurückgreifen.

Unbehandelte Codes wären hingegen sowas wie SQL exceptions, timeouts, tatsächliche Bugs, ..

Und was sollte deiner Meinung nach eine solche Exception dem Client liefern? Nichts? Oder vielleicht doch eher einen konkreten StatusCode (z.B 500)? Wo wir wieder beim Thema ActionResult wären.

beide über den haufen zu wärfen wäre... problematisch

Warum? In deiner Business-Logik fliegt eine konkrete, vllt selbst implementierte Exception, die du in deiner Controller Action fängst und auf dieser Basis einen kontrollierten Status-Code zurückgibst, den der Client dann verarbeiten kann. Sehe dein Problem ehrlich gesagt nicht. Für 500er Szenarien würde ich eine Middleware verwenden.

Es geht wirklich nur um den Compiler, er soll mir anzeigen wenn ich z.B. den Rückgabetyp eines Data Repositories geändert habe und ich deswegen das ActionResult ändern muss. Ich benutze NSWag clients die aus der API Dokumentaiton Typescript und C# clients generieren können. Wenn also der Typ des ActionResult nicht mit dem tatsächlichen Rückgabetyp übereinstimmt heißt es BUMM - bug.

Ich meine, dass Nswag sich nichtmal am konkreten Code orientiert, sondern am Swagger-File, das auf Basis der Definitionen generiert wird, die du mittels Attributes setzt für die versch. StatusCode Möglichkeiten. Sprich dein Rückgabewert der Funktion und das, was Nswag dir generiert können sogar gänzlich asynchron laufen.

Was bei deinen genannten Problemen hilft?
  • Automatisierte ControllerTests
  • Code Reviews
  • Oder wenn du doch so verbissen darauf bist, dass du einen Build-Error bekommst, dann schreib dir doch eigene ActionResults, z.B:

C#:
public class Ok200<T> : OkObjectResult
{
  public Ok200(T value): base(value)
}
 
Zuletzt bearbeitet:
Kokujou schrieb:
aber ein error ist kein return type sondern eine exception
Nein. Eine Exception ist, wie man aus der Übersetzung herleiten kann, eine Ausnahme - KEIN Fehler. Ausnahmen sollte man aus meiner Sicht sparsam einsetzen und sie wenn möglich nicht als Eventbus oder Fehlertransfer-Tool misbrauchen, insbesondere nicht für die Anzeige von Fehlermeldungen im UserInterface. Ausnahmen sind Sachen, die man nicht erwartet - wie z.B. eine Datenbankverbindung, die abreißt, eine Datei, die nicht gelesen werden kann oder wenn die Festplatte voll ist.

Fehler, die man erwartet sind keine Ausnahmen (z.B. Validierungsfehler bei der Falscheingabe einer E-Mail-Adresse). Entgegen der häufigsten Implementierungen können Fehlerantworten (wie z.B. 404) auch noch Daten enthalten. Ich persönlich mag es z.B. bei einem POST Request Validierungsfehler einen 422 Unprocessable Entity zurück zu geben und in der Antwort die fehlerhaften Felder inkl. Nachricht zu senden - oder weitere Metadaten. Das wäre mit Exceptions nur sehr schwierig möglich, weil du entweder den ganzen Kontext des Validierungsfehlers wegwirfst und als einen String in der Nachricht der Exception mit einbauen musst oder dir eine sehr spezielle Exception-Klasse erstellen musst, die den ganzen Kontext unterstützt. Beides nicht optimal. Schau dir das hier vielleicht mal an, das ist wirklich eine tolle library: https://www.jsonapi.net/
Hier die Spezifikation dazu: https://jsonapi.org/

Kokujou schrieb:
Es geht wirklich nur um den Compiler, er soll mir anzeigen wenn ich z.B. den Rückgabetyp eines Data Repositories geändert habe
Wie schon gesagt: Die OperationalResult library leistet hier sehr viel. Nimm lieber Generics mit Constraints, dann hast du die Typprüfung implizit drin, aber sie ist auch erweiterbar:

C#:
void foo<TOne, TTwo>()
   where TOne : BaseOne
   where TTwo : BaseTwo
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: VD90
sandreas schrieb:
Fehler, die man erwartet sind keine Ausnahmen (z.B. Validierungsfehler bei der Falscheingabe einer E-Mail-Adresse). Entgegen der häufigsten Implementierungen können Fehlerantworten (wie z.B. 404) auch noch Daten enthalten. Ich persönlich mag es z.B. bei einem POST Request Validierungsfehler einen 422 Unprocessable Entity zurück zu geben und in der Antwort die fehlerhaften Felder inkl. Nachricht zu senden - oder weitere Metadaten.
ja eben und das kann ich nicht wenn ich einen konkreten Ausgabetyp spezifiziere. Dann hätte ich nur die Möglichkeit eine Exception fliegen zu lassen oder 200 zurückzugeben, das wars mit 200

Und doch, Swagger orientiert sich an dem Code, es wurde ziemlich verbessert. Es liest den generischen Typ des ActionResults und verwandelt diesen automatisch in API Dokumentation genau wie es die HTTPGet/Post/Put/... Attribute und die Funktionsparameter umwandelt. Ich muss z.B. in meinen Endpunkten gar keine Attribute verwenden, sogar dass ich JSON als standardformat verwende erkennt er automatisch durch das im Startup angegebene Plugin fürs MVC

Das Problem dabei ist halt nach wie vor dass ich im ActionResult Typ A angeben kann und trotzdem Ok mit Typ B zurückgeben kann. Was natürlich irgendwo auch sinn macht da du ja explizit willst dass auch BadRequest mit einem anderen Typ, nämlich einem spezialisierten Fehlertyp zurückgeben wird.

Aber gut. Ich lese aus euren Antworten ab dass es hier wohl oder übel nach der Devise gibt "Wenn es nicht da ist, muss ich es bauen." ich hatte gehofft dass dies ein gängiges Problem ist und es da schon vorgefertigte Lösungen gibt. Sowas wie eine BadRequestException der man das Error-Model mitgibt oder so, aber ich schätze das wird so nichts und ich muss es wohl oder übel selber bauen.

Tortzdem danke für eure Antworten und eure Anregungen :)
 
Kokujou schrieb:
Sowas wie eine BadRequestException der man das Error-Model mitgibt oder so, aber ich schätze das wird so nichts und ich muss es wohl oder übel selber bauen.
Eine BadRequestException ist für mich der falsche Weg - den ein BadRequest ist etwas, dass man erwartet und behandelt. Keine Ausnahme. Nur weil du dadurch 2 Zeilen Attribute sparst und Swagger damit besser zurecht kommt, ist es nicht automatisch besser oder richtig. Und bedenke auch, das Exceptions und deren Behandlung nicht gerade der performanteste Weg sind, ein Problem zu lösen. Eher im Gegenteil.
 
  • Gefällt mir
Reaktionen: Camazotz
Ich verlier mich schon wieder in mehreren A4 Seiten XD darüber könnte man stundenlang diskutieren also versuch ich mich kurz zu fassen.

Automatisierte Tests sind bei uns nicht drin, das ist von mehreren Seiten so beschlossen, sowohl im Guten aber eben auch im Schlechten.

Exceptions sind für mich der einzig saubere Weg ein Fehlermodell zu transportieren. Man kann sich über Semantik schreiben aber ich finde Exceptions immer noch schöner als irgendwelche gewrappten Datenobjekte zu haben die vielleicht oder auch nicht einen Fehler enthalten. Wenn das allgemein anerkannt wäre, würden schon längst alle Funktionen so funktionieren und ein deraritges Framework wäre standard. Exception sind standard in so ziemlich allen Programmiersprachen. Ihr habt Rehct sie sind manchmal ziemlich imperformant, was ich ehrlich gesagt kompletten Schwachsinn finde. Essentiell ist eine Exception nichts weiter als ein return Statement mit einem festen Basistyp, also warum müssen ide das unbedingt so einbauen dass irgendein Voodoo die Performance verringert? Ich jedenfalls benutze sie stets als saubere Lösung um aus einer Funktion auszusteigen und trotzdem Fehler zu loggen.

Und das mit dem 1-2 Attribute sparen: In dem Moment wo du für ein Objekt zweimal einen Typ angeben musst hast du bei Clean Code versagt und in dem Moment wo diese typen nicht zwangsweise überein stimmen müssen und ein Build mit unterschiedlichen Typen durchgehen würde ist die Type Safety im Eimer, so einfach ist das. Und Microsoft stimmt mir offenbar zu ansonsten hätten sie nicht den var Typ eingeführt, der inzwischen auf so ziemlich alles ausgeweitet wird.

aber wie gesagt übersowas könnte man sich ewig streiten und vermutlich tun das auch viele Leute
 
Kokujou schrieb:
darüber könnte man stundenlang diskutieren also versuch ich mich kurz zu fassen.
Könnte man - will ich aber eigentlich nicht. Ich wollte nur helfen.

Kokujou schrieb:
Exceptions sind für mich der einzig saubere Weg ein Fehlermodell zu transportieren.
In vielen Sprachen gibt es gar keine Exceptions. Und du sagst damit, all diese Sprachen haben ein unsauberes Fehlermodell.

Kokujou schrieb:
ich finde Exceptions immer noch schöner als irgendwelche gewrappten Datenobjekte zu haben
"Ich finde ... schöner" ist ja deine persönliche Meinung. Dann machs doch so - Ich finde es allerdings schwierig, dir zu "helfen", wenn du mit deiner vorgefertigten Meinung einen Post verfasst, ALLE sagen, dass es vielleicht nicht die beste Idee ist und du dann am Schluss trotzdem dabei bleibst.

Kokujou schrieb:
Wenn das allgemein anerkannt wäre, würden schon längst alle Funktionen so funktionieren und ein deraritges Framework wäre standard. Exception sind standard in so ziemlich allen Programmiersprachen.
if-Abfragen sind "standard" auch in so ziemlich allen Programmiersprachen... ich kann sie trotzdem falsch benutzen. Bei Exceptions ist es durch die höhere Komplexität nur wesentlich einfacher, sie falsch zu benutzen.
Kokujou schrieb:
Ihr habt Rehct sie sind manchmal ziemlich imperformant, was ich ehrlich gesagt kompletten Schwachsinn finde. Essentiell ist eine Exception nichts weiter als ein return Statement mit einem festen Basistyp, also warum müssen ide das unbedingt so einbauen dass irgendein Voodoo die Performance verringert?
Mit dieser Ausführung sieht man, dass du Exceptions noch nicht so richtig durchdrungen hast. Es ist KEIN return-Statement, sondern viel viel komplexer. Die "schlechte Performance" hat einen Grund. Exceptions sind Objekte (groß), die den ganzen Ausführungskontext (groß) mitschleppen müssen und deren Behandlung auch über den Kontext hinaus (groß) erforderlich ist, weil sie nicht an Ort und stelle gefangen oder behandelt werden müssen. Zusätzlich ist ein try/catch statement erforderlich, damit sie dir nicht Unhandled um die Ohren fliegt. Lies das hier mal... das ist sehr informativ: https://docs.microsoft.com/en-us/archive/blogs/cbrumme/the-exception-model
Vielleicht mal ein praktisches Beispiel für den Umfang von Exceptions (für ALLE Leser, nicht nur für dich). Füge mal folgenden Code ein und kompiliere ihn:
C#:
    private int DoSomething()
    {
        try
        {
            return 0;
        }
        finally
        {
            return 1;
        }
    }

Es wird nicht gehen. Weil das finally NACH dem Return ausgeführt werden würde. In manchen Sprachen gibt die Funktion 1 zurück, in manchen fängt es der Compiler ab. Aber 0 wird nie zurück gegeben, weil das finally IMMER ausgeführt wird, sogar nach dem return noch.


Deswegen Finde ich Exceptions nicht so toll. Sie ermöglichen dir, die Fehlerbehandlung an einen anderen Ort zu verlagern oder eben auch EINEN Fehlerhandler für viele viele Fehler zu schreiben bzw. sie komplett zu ignorieren, ohne das der Compiler meckert. Das ist Mist. Fehler behandelt man lieber spezifisch. Es ist mehr Arbeit, aber sehr viel wartungsfreundlicher und verständlicher, den Fehler an Ort und Stelle zu behandeln.

Kokujou schrieb:
Und das mit dem 1-2 Attribute sparen: In dem Moment wo du für ein Objekt zweimal einen Typ angeben musst hast du bei Clean Code versagt und in dem Moment wo diese typen nicht zwangsweise überein stimmen müssen und ein Build mit unterschiedlichen Typen durchgehen würde ist die Type Safety im Eimer, so einfach ist das.
Ohje... mir gefällt deine Argumentation immer weniger. Ich sehe viele Dinge SEHR anders und ich denke ich bin hier raus... wenn Clean Code als Argument kommt, werde ich immer nervös ;-) Die meisten haben das Buch nicht mal gelesen. Falls du es noch nicht gelesen hast (und ich meine wirklich gelesen, so mit in die Hand nehmen und jede Seite verstehen), dann machs mal. Das Buch ist echt gut. Falls doch, nimms vielleicht noch mal in die Hand :-) Und sieh es nicht so dogmatisch was da drin steht, nicht alles dadrin ist allgemeingültig.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: Camazotz und VD90
Zurück
Oben