Ich habe eine Diskussion mit einem Kollegen über Linq. Ich kopiere hier:
Mitarbeiter: Seien wir mal ehrlich. Linq-Syntax ist zum Kotzen. Es ist verwirrend und nicht intuitiv.
Ich: Ach komm schon, verwirrender als T-SQL?
Mitarbeiter: Äh, ja.
Ich: Es hat die gleichen grundlegenden Teile, wählen Sie, wo und von
Mitarbeiter: Linq ist für mich eine Bastardisierung von relational + OO. Mitarbeiter: Verstehen Sie mich nicht falsch - es ist unglaublich leistungsfähig, aber sie haben SQL für die Verwendung von Against-Object-Collections umfunktioniert.
Ich bin der Meinung, dass die Verwendung von Linq + Lamda sehr leistungsfähig ist (er stimmt zu) und auch das Lesen von Code erleichtert (er ist in diesem Punkt anderer Meinung):
pickFiles = from f in pickFolder.GetFiles("*.txt")
where ValidAuditFileName.IsMatch(f.Name)
select f;
oder
var existing = from s in ActiveRecordLinq.AsQueryable<ScannedEntity>()
where s.FileName == f.FullName && s.DocumentType != "Unknown"
select s;
oder (VB Code hier)
Dim notVerified = From image In images.AsParallel
Group Join verifyFile In verifyFolder.GetFiles("*.vfy").AsParallel.Where(
Function(v) v.Length > 0
).AsParallel
On image.Name.Replace(image.Extension, ".vfy") Equals verifyFile.Name
Into verifyList = Group
From verify In verifyList.DefaultIfEmpty
Where verify Is Nothing
Select verify
Für mich ist das klar und einfach (zumindest einfacher als die Alternativen) zu lesen. Wie sind Ihre Meinungen dazu?
quelle
Antworten:
Ich kann den richtigen Post nicht mehr finden, aber Eric Lippert (und möglicherweise mehrere andere Softies) haben mehrmals darüber nachgedacht, wie deklarativ Linq ist , was für verschiedene Problemklassen weitaus intuitiver ist als die imperative Syntax.
Mit Linq können Sie Code schreiben, der die Absicht und nicht den Mechanismus ausdrückt .
Sie sagen mir, was leichter zu lesen ist. Diese:
Oder dieses?
Oder auch das?
Das erste Beispiel ist nur ein Bündel von sinnlosen Boilerplate, um die einfachsten Ergebnisse zu erzielen. Jeder, der glaubt , dass es mehr lesbar als die Linq - Versionen seinen Kopf untersuchen lassen muss. Nicht nur das, sondern der erste verschwendet Speicher. Sie können es
yield return
aufgrund der Sortierung nicht einmal mit schreiben .Ihr Mitarbeiter kann sagen, was er will; Persönlich denke ich, dass Linq meine Code-Lesbarkeit unermesslich verbessert hat .
Es gibt auch nichts "relationales" an Linq. Es mag einige oberflächliche Ähnlichkeiten mit SQL aufweisen, versucht jedoch nicht in irgendeiner Form, eine relationale Rechnung zu implementieren. Es sind nur eine Reihe von Erweiterungen, die das Abfragen und Projizieren von Sequenzen erleichtern. "Abfrage" bedeutet nicht "relational", und es gibt tatsächlich mehrere nicht relationale Datenbanken, die eine SQL-ähnliche Syntax verwenden. Linq ist rein objektorientiert, es funktioniert nur mit relationalen Datenbanken über Frameworks wie Linq to SQL, da einige Ausdrucksbaum-Voodoos und das clevere Design des C # -Teams anonyme Funktionen implizit in Ausdrucksbäume konvertieren.
quelle
Linq is purely object-oriented
+1 dafür. Aus diesem Grund erzwingt unser Team-Styleguide die fließende Syntax gegenüber der Abfragesyntax. Ich finde, das macht die OO-Natur der Verknüpfung für jemanden offensichtlicher, der die Objektnotation in C-ähnlichen Sprachen verwendet.GetVipCustomers()
, was, wie der Name schon sagt, nur eine Sammlung von VIP-Kunden in willkürlicher Reihenfolge zurückliefert. In seltenen Fällen, in denen die Reihenfolge wichtig ist, z. B. bei der Ausgabe auf dem Bildschirm, kann der Anrufer die Sammlung sortieren.Mit dieser Kritik kann man nicht streiten. Für Ihren Mitarbeiter ist es scheiße . Es ist uns nicht gelungen, eine Syntax zu entwerfen, die für sie klar und intuitiv ist. Das ist unser Versagen, und Sie können sich bei Ihrem Kollegen entschuldigen. Gerne nehme ich Vorschläge zur Verbesserung entgegen. was konkret findet ihr mitarbeiter verwirrend oder uninteressant?
Sie können jedoch nicht allen gefallen. Meine persönliche Meinung und die Meinung der meisten Leute, mit denen ich über dieses Thema gesprochen habe, ist, dass die Syntax des Abfrageverständnisses viel klarer ist als die entsprechende imperative Syntax. Natürlich sind sich nicht alle einig, aber zum Glück brauchen wir nicht den Konsens aller Millionen unserer Kunden, wenn wir Sprachdesign betreiben.
In Bezug auf das, was "intuitiv" ist, erinnere ich mich an die Geschichte des englischen Linguisten, der viele verschiedene Sprachen studierte und schließlich zu dem Schluss kam, dass Englisch die beste aller Sprachen ist, da die Wörter auf Englisch in derselben Reihenfolge wie Sie vorkommen denke sie . Im Gegensatz zu Französisch, wo sie ständig Dinge sagen wie "der Hund weiß isst das Fleisch rot". Wie schwer muss es für die Franzosen sein , die Wörter in der richtigen Reihenfolge zu denken und sie dann in der französischen Reihenfolge zu sagen ! Französisch ist so unintuitiv! Es ist erstaunlich, dass die Franzosen es schaffen, es zu sprechen. Und deutsch? wo sie denken "der hund frisst das fleisch" aber dann müssen sie sagen "der hund frisst das fleisch"!?!
Was "intuitiv" ist, ist oft nur eine Frage der Vertrautheit. Es hat Monate gedauert, bis ich mit LINQ gearbeitet habe und meine Abfragen nicht mehr mit der "select" -Klausel begonnen habe. Jetzt ist es eine zweite Natur, und die SQL-Reihenfolge scheint bizarr.
Was es ist! Die Scoping-Regeln sind alle in SQL durcheinander. Möglicherweise möchten Sie Ihren Kollegen darauf hinweisen, dass LINQ sorgfältig so konzipiert wurde, dass (1) die Einführung von Variablen und Bereichen von links nach rechts erfolgt (*) und (2) die Reihenfolge, in der die Abfrage auf der Seite angezeigt wird die Reihenfolge, in der es ausgeführt wird. Das heißt, wenn Sie sagen
Das c wird links im Bereich angezeigt und bleibt rechts im Bereich. Und die Reihenfolge, in der die Dinge geschehen, ist: Zuerst werden "Kunden" bewertet. Dann wird das "wo" ausgewertet, um die Sequenz zu filtern. Dann wird die gefilterte Sequenz von der "Auswahl" projiziert.
SQL hat diese Eigenschaft nicht. Wenn du sagst
dann wird "Name" durch etwas zu seiner Rechten und nicht zu seiner Linken in den Geltungsbereich gebracht, und die Abfrage wird in einer völlig durcheinandergebrachten Reihenfolge ausgeführt; Die mittlere Klausel wird zuerst ausgewertet, dann die letzte Klausel und dann die erste Klausel. Das erscheint mir jetzt verrückt und uninteressant, da ich schon so lange ausschließlich mit LINQ gearbeitet habe.
(*) Gültigkeitsregeln sind in LINQ mit Join-Klauseln etwas seltsam. Davon abgesehen sind die Bereiche gut verschachtelt.
quelle
c.
kennt die IDE zum Zeitpunkt der Eingabe bereits den Typc
und kann Ihnen IntelliSense geben. In LINQ sagen Sie "von c in Kunden, bei denen c." und boom, Sie bekommen IntelliSense, das Ihnen hilft, indem es die Mitglieder von auflistetCustomer
. Wenn Sie in SQL "SELECT name FROM customers" eingeben, erhalten Sie keine IDE-Hilfe, die Ihnen mitteilt, dass "name" eine gute Wahl ist, da Siename
zuvor etwas eingegeben habencustomers
.Wie alles andere in der Programmierwelt muss man sich an die Syntax gewöhnen, und dann ist es (möglicherweise) einfacher zu lesen.
Wie bei allem anderen in der Programmierwelt besteht die Möglichkeit von Spaghetti-Code oder anderen Missbräuchen.
Wie alles in der Programmierwelt können Sie dies entweder auf diese oder eine andere Weise tun.
Wie alles in der Programmierwelt kann auch Ihr Kilometerstand variieren.
quelle
Ich habe einen Kommentar / eine Bemerkung gesehen, in dem / der etwas - in Bezug auf LINQ / Lambda - stand: "Schreiben Sie Code, der für Menschen lesbar ist, anstatt für Ihren Computer lesbar".
Ich denke, dass diese Aussage eine Menge Verdienst hat, bedenken Sie jedoch den Entwickler (wie mich), der die gesamte Bandbreite der Entwicklungssprachen von Assembly über prozedural, über OO, durch verwaltet und durch die Nutzung von parallelen Lösungen für Aufgaben mit hohem Durchsatz durchlaufen hat .
Ich bin stolz darauf, meinen Code so lesbar und wiederverwendbar wie möglich zu machen und viele der GOF-Entwurfsmusterprinzipien anzuwenden, um Systeme und Dienstleistungen für die Produktionsqualität in einer Vielzahl unterschiedlicher Geschäftsbereiche bereitzustellen.
Als ich das erste Mal auf den Lambda-Ausdruck stieß, dachte ich: "Was zum Teufel ist das!?!" Es war meiner vertrauten (und daher bequemen) expliziten deklarativen Syntax sofort zuwider. Die jüngeren <5-Jährigen im Job haben es jedoch geschafft, als wäre es Manna vom Himmel!
Das liegt daran, dass jahrelanges Denken wie ein Computer (im syntaktischen Sinne) sehr einfach in direkte Codierungssyntax (unabhängig von der Sprache) übersetzt werden kann. Wenn Sie diese rechnerische Denkweise seit über 20 Jahren (in meinem Fall über 30) haben, müssen Sie sich darüber im Klaren sein, dass der anfängliche syntaktische Schock des Lambda-Ausdrucks leicht zu Angst und Misstrauen führen kann.
Vielleicht hatte der Mitarbeiter im OP einen ähnlichen Hintergrund wie ich (dh war ein paar Mal in der Nähe des Blocks) und es war zu diesem Zeitpunkt für ihn nicht intuitiv? Meine Frage ist: Was hast du dagegen getan? Haben Sie versucht, Ihren Kollegen dazu zu erziehen, die Vorteile der Inline-Syntax zu verstehen, oder haben Sie sie angeprangert / ausgegrenzt, weil sie nicht "mit dem Programm" zusammen sind? Ersteres hätte wahrscheinlich Ihren Kollegen dazu gebracht, sich Ihrer Meinung anzunähern, letzteres würde ihn wahrscheinlich dazu bringen, der LINQ / Lambda-Syntax noch mehr zu misstrauen und damit die negative Meinung zu verschärfen.
Für mich selbst musste ich meine eigene Denkweise umerziehen (wie Eric oben schlussfolgert, ist dies keine unbedeutende Veränderung des Denkvermögens, und ich musste in den 80er Jahren in Miranda programmieren, damit ich über einen Teil meiner Erfahrung mit funktionaler Programmierung verfügte). aber sobald ich durch diesen Schmerz gegangen war , die Vorteile liegen auf der Hand , aber - was noch wichtiger ist - wo seine Verwendung wurde über verwendet (dh zum Zwecke verwendet , es zu benutzen), über komplexe und sich wiederholende ( unter Berücksichtigung der DRY - Prinzip in diesem Beispiel).
Als jemand, der nicht nur noch viel Code schreibt, sondern auch technisch viel Code überprüfen muss, war es unbedingt erforderlich, dass ich diese Prinzipien verstehe, damit ich Artikel unparteiisch überprüfen und beraten kann, wo die Verwendung eines Lambda-Ausdrucks effizienter sein kann / lesbar, und um Entwickler zu veranlassen, die Lesbarkeit hochkomplexer Inline-Lambda-Ausdrücke zu berücksichtigen (wobei ein Methodenaufruf in diesen Fällen den Code lesbarer, wartbarer und erweiterbarer machen würde).
Also, wenn jemand sagt, dass er kein Lambda bekommt? oder LINQ-Syntax, anstatt sie als ludditisch zu bezeichnen, um ihnen zu helfen, die zugrunde liegenden Prinzipien zu verstehen. Sie haben vielleicht doch einen "old school" Hintergrund wie ich.
quelle
Lambda-Ausdrücke führen zu weniger lesbarem Code, wenn Abfragen zu lang sind. Es ist jedoch viel besser als zu viele verschachtelte Schleifen .
Es ist besser mit einer Mischung aus beiden .
Schreiben Sie es in Lambda, wenn es schneller ist (Sie brauchen es, um schnell zu sein) oder leichter zu lesen.
quelle
Ich denke, es hängt in den meisten Fällen (außer wenn man etwas sehr Bizarres macht) davon ab, ob man "lesbar" meint, wenn jemand die Idee hat, was los ist, oder ob er leicht all die kleinen Details findet.
Ich denke, Link hilft bei ersteren, aber oft (besonders beim Debuggen) schadet letzteren.
IMHO, wenn ich Code betrachte, bin ich mit dem ersteren nicht vertraut, das ist enorm wichtiger als das letztere, also finde ich es viel lesbarer.
quelle
where e.FirstName == "John"
und in eine SQL-Abfrage umgewandelt! Dies geschieht, indem Sie den nicht kompilierten (aber analysierten) Ausdruck betrachten und feststellen, dass es sich um einen Vergleich einer Eigenschaft handelt, dieFirstName
für eine persistierte Entität aufgerufen wurde , und die mit einer Zeichenfolge usw. verglichen wird. Es ist viel los.Ich finde die LINQ-Syntax intuitiv und einfach zu lesen, zumal sie das FROM am Anfang dort platziert, wo es hingehört, anstatt wie in SQL in der Mitte. Aber IMO-Lambdas sind verwirrend und erschweren das Lesen des Codes.
quelle
\x -> x * x
) oder F # (fun x -> x * x
)?Ich stimme Ihnen zu, dass sich die Linq-Syntax nicht wesentlich von T-SQL unterscheidet. Ich denke, Ihr Kollege könnte wirklich Einwände gegen relationale Dinge erheben, in die sein netter und glänzender OO-Code eingemischt wird. Andererseits ist die funktionale Programmierung gewöhnungsbedürftig und gewöhnungsbedürftig.
quelle
Es hängt davon ab, ob. Offensichtlich bietet T-SQL in einzigartiger Weise einige relationale DB-Lösungen. Natürlich bietet LINQ auf einzigartige Weise einige OO-Lösungen.
Jedoch; "verwirrender als T-SQL?" - wird in der Ausgangsfrage besprochen / gestellt. Dies impliziert eindeutig einige Merkmale, die in keiner der vorhandenen Antworten angesprochen werden, und wirft dem (offensichtlich SQL-vertrauten) Kritiker stattdessen vor, in der Vergangenheit festzustecken.
Obwohl ich LINQ für bestimmte Eigenschaften schätze und mit den vorhandenen Antworten hier nicht sehr einverstanden bin, denke ich, dass der Kontrapunkt eine Repräsentation verdient:
Jahre, nachdem ich mich mit LINQ vertraut gemacht habe, erschrecken mich bestimmte Arten von Gruppenoperationen, Outer Joins und Nicht-Equijoins, die Arbeit mit zusammengesetzten Schlüsseln und andere Operationen in LINQ immer noch. (Insbesondere, wenn Sie ein relationales Back-End mit leistungsbezogenen Fragen ansprechen.)
Wenn du denkst, dass das intuitiv ist, hast du mehr Kraft. ;)
quelle
Es gibt wahrscheinlich einen Grund, warum Linq scheiße ist. Versuchen Sie einfach, Beispiele aus der realen Welt zu machen, anstatt diese Lehrbuchbeispiele.
Wenn Sie versuchen, diese Funktion in Linqlamdathings zu zeigen, werden Sie feststellen, dass die gesamte Schönheit verschwunden ist, während der klassische Weg lesbar bleibt. Ganz zu schweigen von verzögerten Ausführungsproblemen und dem Setzen von Haltepunkten.
Die Wahrheit ist, dass LinqLambdaThings in wenigen Fällen sehr nützlich sind und nicht die raffinierte Objektorientierung ersetzen sollen, die ihr noch nie verstanden habt
quelle
source.Where(c => c.IsVip && c.FirstName == "Aaron" || c.SecondName == "Aaron").Take(maxCount).OrderBy(d => d.LastName);
aber schwer deine zu lesen, also habe ich vielleicht einen Fehler gemacht;)