434 Stimmen

Reflektierende Parameternamen: Missbrauch von C#-Lambda-Ausdrücken oder brillante Syntax?

Ich betrachte die MvcContrib Grid-Komponente und ich bin fasziniert und gleichzeitig abgestoßen von einem syntaktischen Trick, der in der Gittersyntax :

.Attributes(style => "width:100%")

Die obige Syntax setzt das style-Attribut des generierten HTML auf width:100% . Wenn Sie genau hinschauen, ist "Stil" nirgends angegeben. Er wird abgeleitet aus dem Name des Parameters im Ausdruck! Ich musste nachforschen und fand heraus, wo die "Magie" passiert:

Hash(params Func<object, TValue>[] hash)
{
    foreach (var func in hash)
    {
        Add(func.Method.GetParameters()[0].Name, func(null));
    }
}

Der Code verwendet also in der Tat den formalen Namen der Parameter zur Kompilierungszeit, um das Wörterbuch der Attribut-Name-Wert-Paare zu erstellen. Das daraus resultierende Syntaxkonstrukt ist in der Tat sehr ausdrucksstark, aber gleichzeitig auch sehr gefährlich.

Die allgemeine Verwendung von Lambda-Ausdrücken ermöglicht die Ersetzung der Namen ohne Nebenwirkung verwendet werden. Ich sehe ein Beispiel in einem Buch, das sagt collection.ForEach(book => Fire.Burn(book)) Ich weiß, dass ich in meinen Code schreiben kann collection.ForEach(log => Fire.Burn(log)) y es bedeutet dasselbe . Aber mit der MvcContrib Grid-Syntax finde ich plötzlich Code, der aktiv nach den Namen sucht und Entscheidungen trifft, die ich für meine Variablen wähle!

Also ist dies gängige Praxis mit der C# 3.5/4.0-Gemeinschaft und die Lambda-Ausdrücke Liebhaber? Oder handelt es sich um einen abtrünnigen Außenseiter, über den ich mir keine Sorgen machen sollte?

10 Stimmen

+1 für die Einführung der Hash-Rakete in C#

2 Stimmen

Foreach (var func in hash) ändern in: Array.ForEarch(hash, func => Add(func.Method.GetParameters()[0].Name, func(null)));

34 Stimmen

Ich würde behaupten, dass dies offensichtlich ist, solange man bereit ist, die Absicht des Codes zu betrachten und nicht nur die Syntax zu analysieren. Wenn Sie guten Code lesen, sollten Sie das ohnehin tun. Die Syntax ist nur ein Vehikel für die Intention, und ich würde behaupten, dass dies ein Code ist, der die Intention offenbart.

18voto

citizenmatt Punkte 17544

Darf ich damit einen Begriff prägen?

magic lambda (n): eine Lambda-Funktion, die ausschließlich dazu dient, eine magische Zeichenfolge zu ersetzen.

0 Stimmen

Yeah... das ist lustig. und vielleicht ist es magisch irgendwie, im Sinne von keine Kompilierzeit Sicherheit, gibt es einen Ort, wo diese Verwendung Laufzeit statt Kompilierzeit Fehler verursachen würde?

17voto

Tommy Carlier Punkte 7563

Was ist an den folgenden Punkten falsch?

html.Attributes["style"] = "width:100%";

16voto

Charlie Flowers Punkte 17000

All dieses Geschimpfe über "Abscheulichkeit" ist ein Haufen langjähriger C#-Programmierer, die überreagieren (und ich bin ein langjähriger C#-Programmierer und immer noch ein großer Fan der Sprache). Es gibt nichts Schreckliches an dieser Syntax. Es ist lediglich ein Versuch, die Syntax so zu gestalten, dass sie mehr dem entspricht, was man ausdrücken will. Je weniger "Rauschen" es in der Syntax für etwas gibt, desto leichter kann der Programmierer es verstehen. Die Verringerung des Rauschens in einer Codezeile hilft nur ein wenig, aber wenn man das über mehr und mehr Code aufbaut, stellt sich heraus, dass es ein wesentlicher Vorteil ist.

Dies ist ein Versuch des Autors, die gleichen Vorteile anzustreben, die DSLs bieten - wenn der Code einfach "wie" das aussieht, was man zu sagen versucht, hat man einen magischen Ort erreicht. Man kann darüber diskutieren, ob dies gut für die Interoperabilität ist, oder ob es schöner ist als anonyme Methoden, um die Kosten der "Komplexität" zu rechtfertigen. In Ihrem Projekt sollten Sie die richtige Entscheidung treffen, ob Sie diese Art von Syntax verwenden wollen. Aber dennoch ... dies ist ein kluger Versuch eines Programmierers, das zu tun, was wir letztendlich alle versuchen zu tun (ob wir es realisieren oder nicht). Und was wir alle zu tun versuchen, ist dies: "Dem Computer zu sagen, was er tun soll, und zwar in einer Sprache, die unseren Vorstellungen so nahe wie möglich kommt.

Der Schlüssel zu einer besseren Wartbarkeit und Genauigkeit von Software liegt darin, dass wir unsere Anweisungen gegenüber Computern auf dieselbe Weise ausdrücken, wie wir selbst denken.

EDIT: Ich hatte gesagt "der Schlüssel, um Software wartbarer und genauer zu machen", was ein wahnsinnig naives, übertriebenes Stück Einhorn ist. Ich habe es in "ein Schlüssel" geändert.

12voto

Jamie Penney Punkte 9110

Dies ist einer der Vorteile von Ausdrucksbäumen - man kann den Code selbst auf zusätzliche Informationen untersuchen. Das ist der Grund .Where(e => e.Name == "Jamie") kann in die entsprechende SQL-Where-Klausel umgewandelt werden. Dies ist eine clevere Verwendung von Ausdrucksbäumen, obwohl ich hoffen würde, dass es nicht weiter als bis hierher geht. Alles, was komplexer ist, wird wahrscheinlich schwieriger sein als der Code, den es zu ersetzen hofft, so dass ich vermute, dass es eine Selbstbeschränkung sein wird.

0 Stimmen

Das ist ein berechtigtes Argument, aber Wahrheit in der Werbung: LINQ kommt mit einer ganzen Reihe von Attributen wie TableAttribute und ColumnAttribute, die dies eine legitime Angelegenheit machen. Außerdem betrachtet LINQ Mapping die Klassennamen und Eigenschaftsnamen, die wohl stabiler sind als Parameternamen.

0 Stimmen

Da stimme ich Ihnen zu. Ich habe meine Haltung zu diesem Thema etwas geändert, nachdem ich gelesen habe, was Eric Lippert/Anders Helsberg/etc. zu diesem Thema zu sagen hatten. Ich dachte, ich lasse diese Antwort hier, da sie immer noch einigermaßen hilfreich ist. Ich denke jetzt, dass diese Art, mit HTML zu arbeiten, zwar nett ist, aber nicht zu der Sprache passt.

8voto

davidfowl Punkte 34276

Das ist ein interessanter Ansatz. Wenn Sie die rechte Seite des Ausdrucks auf Konstanten beschränken würden, könnten Sie mit

Expression<Func<object, string>>

Was ich denke, ist, was Sie wirklich anstelle des Delegaten wollen (Sie verwenden die Lambda, um Namen von beiden Seiten zu erhalten) Siehe naive Implementierung unten:

public static IDictionary<string, string> Hash(params Expression<Func<object, string>>[] hash) {
    Dictionary<string, string> values = new Dictionary<string,string>();
    foreach (var func in hash) {
        values[func.Parameters[0].Name] = ((ConstantExpression)func.Body).Value.ToString();
    }
    return values;
}

Dies könnte sogar das Problem der sprachenübergreifenden Interoperabilität lösen, das weiter oben in diesem Thread erwähnt wurde.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X