Ich muss eine Lösung für eine Aufgabe entwerfen, und ich möchte etwas verwenden, das C # 's ExpressionVisitor theoretisch ähnlich ist.
Aus Neugierde habe ich die .NET-Quellen für ExpressionVisitor
geöffnet, um einen Blick darauf zu werfen. Seit dieser Zeit frage ich mich, warum das .NET-Team den Besucher so implementiert hat wie sie.
Zum Beispiel sieht MemberInitExpression.Accept
folgendermaßen aus:
Meine - wahrscheinlich noob - Frage ist: macht es irgendeinen Sinn? Ich meine, sollte nicht die Accept-Methode selbst dafür verantwortlich sein, wie sie den Besuch in sich selbst umsetzt? Ich meine, ich habe so etwas erwartet (die internal
Sichtbarkeit kann von außen nicht überschrieben werden):
Aber dieser Code ist in der Methode ExpressionVisitor
von VisitMemberInit
, die von MemberInitExpression.Accept
aufgerufen wird. Es scheint also keinen Vorteil der Accept
Umsetzung hier zu geben.
Warum verarbeiten Sie nicht einfach den Baum in der Basis ExpressionVisitor
und vergessen Sie alle Accept
Methoden?
Ich hoffe, Sie verstehen meine Punkte und hoffen, dass jemand die Motivation hinter dieser Umsetzung beleuchten könnte. Vermutlich verstehe ich das Besuchermuster überhaupt nicht? ...
Ein Besucher kann die Art und Weise, wie ein Ausdruck besucht wird, überschreiben. Wenn Ihr Vorschlag an allen Orten implementiert wurde, würde der Besucher nie aufgerufen werden. Die gesamte Besuchslogik wäre in den Überschreibungen von Accept
enthalten. Nicht-BCL-Code kann diese Methode nicht überschreiben.
Wenn Sie visitor.Visit((Expression)this.SomeExpression)
schreiben (wie Sie es in der Frage tun), wie werden Sie den dynamischen Versand für den Typ SomeExpression
durchführen? Jetzt muss der Besucher den dynamischen Versand durchführen. Beachten Sie, dass Ihr zweites Code-Snippet die vereinfachende Annahme macht, dass alle zu durchsuchenden Unter-Ausdrücke einen bekannten Typ haben. Versuchen Sie, den Code für BinaryExpression
zu schreiben, um zu sehen, was ich meine.
Vielleicht habe ich etwas nicht verstanden, aber dieser Vorschlag macht keinen Sinn.
Der Zweck der Methode Accept
ist eine Leistungsoptimierung. Jedes Akzeptieren ist ein virtueller Anruf, der ziemlich billig ist. Die Alternative wäre, einen großen Schalter im Besucher über den Ausdruckstyp zu haben (der eine Aufzählung ist). Das ist wahrscheinlich langsamer.
Das Besuchermuster erlaubt es, den Algorithmus im Wesentlichen von der Struktur zu trennen, auf der er arbeitet. In diesem Fall ist die Struktur, auf der es operiert, der Ausdrucksbaum.
Beachten Sie, dass die Methode Accept
im Besucher virtual
ist. Dies bedeutet, dass wir möglicherweise verschiedene Implementierungen von ExpressionVisitor
schreiben könnten, die verschiedene Dinge in einem Ausdrucksbaum machen (und tatsächlich gibt es verschiedene Implementierungen). Und wir können dies tun, ohne irgendeinen Code in den Ausdrucksbaum-Klassen selbst zu ändern.
Beispiele für verschiedene Besucherimplementierungen können etwa so aussehen, als hätten Sie einen Besucher, der den Ausdrucksbaum wieder in eine Zeichenfolge verwandelt, die C # -Code (oder vielleicht Code in einer anderen Sprache) darstellt.
Tags und Links c# design-patterns linq-expressions visitor-pattern