was ist der sinn des pimpl-musters, während wir die schnittstelle in c ++ für denselben zweck verwenden können?
<p>ich sehe viel quellcode, der pimpl-idiom in c++ verwendet. ich gehe davon aus, dass der zweck darin besteht, die privaten daten/typen/implementierungen auszublenden, um die abhängigkeit zu beseitigen und dann die kompilierungszeit und das problem mit dem header-include zu reduzieren.</p><p>schnittstellen-/rein abstrakte klassen in c++ verfügen jedoch auch über diese funktion. sie können auch zum ausblenden von daten/typ/implementierung verwendet werden. damit der aufrufer beim erstellen eines objekts nur die schnittstelle sehen kann, können wir im header der schnittstelle eine factory-methode deklarieren.</p><p>der vergleich ist:</p><ol> <li> <p><strong>kosten</strong>:</p> <p>die kosten für die schnittstellenmethode sind niedriger, da sie nicht einmal die implementierung der öffentlichen wrapper-funktion <code>void bar::dowork() { return m\_impl-&gt;dowork(); }</code> wiederholen müssen, sondern nur die signatur in der schnittstelle definieren müssen.</p> </li> <li> <p><strong>gut verstanden</strong>:</p> <p>die schnittstellentechnologie wird von jedem c++ - entwickler besser verstanden.</p> </li> <li> <p><strong>leistung</strong>:</p> <p>die leistung der schnittstelle ist nicht schlechter als die pimpl-sprache, beides ein zusätzlicher speicherzugriff. ich gehe davon aus, dass die leistung gleich ist.</p> </li> </ol><p>das folgende ist der pseudocode, um meine frage zu veranschaulichen:</p><pre><code>// forward declaration can help you avoid include barimpl header, and those included in barimpl header. class barimpl; class bar { public: // public functions void dowork(); private: // you don't need to compile bar.cpp after changing the implementation in barimpl.cpp barimpl* m\_impl; }; </code></pre><p>der gleiche zweck kann über die schnittstelle implementiert werden:</p><pre><code>// bar.h class ibar { public: virtual ~ibar(){} // public functions virtual void dowork() = 0; }; // to only expose the interface instead of class name to caller ibar* createobject(); </code></pre><p>was ist der sinn von pimpl?</p>
<p>erstens wird pimpl normalerweise für nicht polymorphe klassen verwendet. und wenn eine polymorphe klasse pimpl hat, bleibt sie normalerweise polymorph, dh sie implementiert immer noch schnittstellen und überschreibt virtuelle methoden aus der basisklasse und so weiter. die einfachere implementierung von pimpl ist also <em> keine </em> schnittstelle, sondern eine einfache klasse, die die mitglieder direkt enthält!</p><p>es gibt drei gründe, pimpl zu verwenden:</p><ol> <li> <p>die <em> binäre </em> schnittstelle (abi) unabhängig von den privaten mitgliedern machen. es ist möglich, eine gemeinsam genutzte bibliothek zu aktualisieren, ohne den abhängigen code neu zu kompilieren, jedoch nur, solange die <em> binäre </em> schnittstelle dieselbe bleibt. jetzt ändert fast jede änderung im header, außer dem hinzufügen einer nicht-mitgliedsfunktion und dem hinzufügen einer nicht-virtuellen mitgliedsfunktion, den abi. das pimpl-idiom verschiebt die definition der privaten mitglieder in die quelle und entkoppelt somit den abi von ihrer definition. siehe <a href="http://c2.com/cgi/wiki?fragilebinaryinterfaceproblem">fragile binary interface problem</a> </p> </li> <li> <p>wenn sich ein header ändert, müssen alle quellen einschließlich des headers neu kompiliert werden. und die c++ - kompilierung ist ziemlich langsam. durch das verschieben von definitionen der privaten mitglieder in die quelle reduziert das pimpl-idiom die kompilierungszeit, da weniger abhängigkeiten in den header gezogen werden müssen, und die kompilierungszeit nach änderungen noch weiter, da die abhängigen elemente nicht neu kompiliert werden müssen (ok, dies gilt auch für die schnittstelle + factory-funktion mit versteckter betonklasse).</p> </li> <li> <p>für viele klassen in c++ ist die ausnahmesicherheit eine wichtige eigenschaft. oft müssen sie mehrere klassen in einer zusammenstellen, damit bei einem vorgang mit mehr als einem element keines der mitglieder geändert wird oder wenn sie eine operation haben, die das mitglied in einem inkonsistenten zustand belässt, wenn es ausgelöst wird und das enthaltende objekt erhalten bleiben muss konsistent. in diesem fall implementieren sie die operation, indem sie eine neue instanz des pimpl erstellen und diese austauschen, wenn die operation erfolgreich ist.</p> </li> </ol><p>tatsächlich kann die schnittstelle auch nur zum ausblenden der implementierung verwendet werden, hat jedoch folgende nachteile:</p><ol> <li> <p>durch das hinzufügen einer nicht virtuellen methode wird abi nicht beschädigt, durch hinzufügen einer virtuellen methode jedoch. schnittstellen erlauben daher überhaupt kein hinzufügen von methoden, pimpl tut dies.</p> </li> <li> <p>inteface kann nur über zeiger/referenz verwendet werden, daher muss der benutzer für eine ordnungsgemäße ressourcenverwaltung sorgen. andererseits sind klassen, die pimpl verwenden, immer noch werttypen und behandeln die ressourcen intern.</p> </li> <li> <p>versteckte implementierung kann nicht vererbt werden, klasse mit pimpl kann.</p> </li> </ol><p>und natürlich hilft die benutzeroberfläche nicht bei der ausnahmesicherheit. dazu benötigen sie die indirektion innerhalb der klasse.</p>
<p>c hat den vorteil, dass es eine relativ <strong> <em> kleine sprache</em> </strong> ist, was es <strong> macht ) <em> einfach einen c-compiler zu implementieren</em> </strong> (während ein c++ - compiler ein monster zum schreiben ist), und macht es <strong> = <em> leichter die sprache zu lernen</em> </strong>. siehe auch <a href="https://www.tiobe.com/tiobe-index/">tiobe-index</a> , wonach c etwas vor c++ liegt.</p><p>in (imo) abnehmender reihenfolge der rechtfertigung wird c immer noch häufig verwendet</p><ul> <li> <p>eingebettetes zeug<br> es ist viel einfacher, einen c-compiler auf eine kleine plattform zu portieren, als einen c++ - compiler zu portieren. außerdem behaupten c-befürworter, dass c++ "hinter ihrem rücken zu viel tut". allerdings imo das ist fud.</p> </li> <li> <p>systemprogrammierung<br> auch dies ist normalerweise auf die behauptung zurückzuführen, dass es einfacher ist, "zu wissen, was der compiler tut". viele eingebettete programme würden jedoch beispielsweise von vorlagen und anderen c++ - schlüsselfunktionen profitieren.</p> </li> <li> <p>quelloffene software<br> das ist jedoch meistens ein einstellungsproblem: oss hat c immer c++ vorgezogen (während es in großen teilen der branche das gegenteil ist). torvalds irrationaler hass könnte tatsächlich der wichtigste grund dafür sein <em> unter linux</em>.</p> </li> </ul> Kein kurzer Schnitt, sondern kapselt dies in eine Funktion ein, und Ihr Code ist viel lesbarer. <p>wenn dies meine entwurfsentscheidung wäre, würde ich wahrscheinlich eher eine option c (modifizierte option a) wählen.</p><h3>erstens, warum nicht 'option b':</h3><p>zum einen gefällt mir die klarheit, dass jedes produkt seinen eigenen tisch hat. wenn es sich nur um eine große tabelle mit einem feld zur bestimmung des typs handelt, ist die beziehung nicht so klar.</p><p>zum anderen würde die indizierungsstrategie immer erfordern, dass dieses typfeld aufgelistet wird. da es sich nur um 4 typen handelt, ist die indexkardinalität extrem niedrig (<code>select * from product\_table where type='x'</code> führt im grunde sowieso einen vollständigen tabellenscan durch)</p><h3>option c.</h3><ul> <li>erstellen sie eine übergeordnete tabelle, die nur die spalten enthält, die alle typen gemeinsam nutzen</li> <li>erstellen sie jeden produkttyp als eigene tabelle mit ihren einzelnen spalten, mit einem zusätzlichen: ein link zur übergeordneten tabelle</li> <li>erstellen sie jede 'link'-tabelle: product\_option, model\_option usw. mit links zu den jeweiligen schlüsseln.</li> <li>für diejenigen mit wechselseitigen links (model\_option, option\_model) erstellen sie auch diese tabellen. dies erhöht die klarheit ihrer joins für alle, die sich das ansehen.</li> </ul><p>der nachteil ist die komplexität, sicherzustellen, dass waisen vermieden werden, wenn dinge aktualisiert/gelöscht werden, und zunächst die abfragen zu entwerfen, die diese tabellen verwenden.</p> <p>emulation ist der prozess der nachahmung des äußerlich beobachtbaren verhaltens, um ein vorhandenes ziel zu erreichen. der interne zustand des emulationsmechanismus muss den internen zustand des ziels, das er emuliert, nicht genau widerspiegeln.</p><p>bei der simulation hingegen wird der zugrunde liegende zustand des ziels modelliert. das endergebnis einer guten simulation ist, dass das simulationsmodell das ziel emuliert, das es simuliert.</p><p>im idealfall sollten sie in der lage sein, in die simulation zu schauen und eigenschaften zu beobachten, die sie auch sehen würden, wenn sie in das ursprüngliche ziel schauen würden. in der praxis kann es aus leistungsgründen einige verknüpfungen zur simulation geben, dh, einige interne aspekte der simulation können tatsächlich eine emulation sein.</p><p>mame ist ein arcade-emulator. hyperterm ist ein (nicht sehr guter) terminalemulator. es ist nicht erforderlich, den arcade-automaten oder ein terminal detailliert zu modellieren, um das gewünschte emulierte verhalten zu erzielen.</p><p>flight simulator ist ein simulator; spice ist ein elektroniksimulator. sie modellieren so weit wie möglich jedes detail des ziels, um darzustellen, was das ziel in der realität tut.</p><p>bearbeiten: andere antworten haben darauf hingewiesen, dass das ziel einer emulation darin besteht, das emulierte objekt zu ersetzen. das ist ein wichtiger punkt. der fokus einer simulation liegt mehr auf der modellierung des internen zustands des ziels - und die simulation führt nicht unbedingt zu einer emulation. insbesondere kann eine simulation viel langsamer als in echtzeit ablaufen. beispielsweise kann spice keinen tatsächlichen elektronischen schaltkreis ersetzen (selbst wenn angenommen wird, dass es eine art magisches gerät gibt, das elektrische schaltkreise perfekt mit einer spice-simulation verbindet.) eine simulation eine simulation führt nicht immer zu einer emulation -</p> <h2>moderne html5-techniken zum ändern von klassen</h2><p>moderne browser haben <a href="https://developer.mozilla.org/en-us/docs/dom/element.classlist"><strong>classlist</strong></a> hinzugefügt, das methoden zur verfügung stellt, mit denen klassen leichter ohne bibliotheken bearbeitet werden können:</p><pre><code>document.getelementbyid("myelement").classlist.add('myclass'); document.getelementbyid("myelement").classlist.remove('myclass'); if ( document.getelementbyid("myelement").classlist.contains('myclass') ) document.getelementbyid("myelement").classlist.toggle('myclass'); </code></pre><p>leider funktionieren diese in internet explorer vor version 10 nicht, obwohl es ein <a href="http://en.wikipedia.org/wiki/shim\_(computing)">shim</a> gibt, um die unterstützung für ie8 und ie9 hinzuzufügen, die unter <a href="https://developer.mozilla.org/en-us/docs/dom/element.classlist">diese seite</a> verfügbar ist. es wird jedoch immer mehr <a href="http://caniuse.com/#feat=classlist">unterstützt</a> .</p><h2>einfache browserübergreifende lösung</h2><p>die standard-javascript-methode zur auswahl eines elements ist <a href="https://developer.mozilla.org/en-us/docs/dom/document.getelementbyid"><code>document.getelementbyid("id")</code></a> . dies wird in den folgenden beispielen verwendet. sie können elemente natürlich auch auf andere weise erhalten. in der richtigen situation können sie stattdessen einfach <code>this</code> verwenden ins detail geht dies nicht in den rahmen der antwort.</p><h3>so ändern sie alle klassen für ein element:</h3><p>um alle vorhandenen klassen durch eine oder mehrere neue klassen zu ersetzen, legen sie das classname-attribut fest:</p><pre><code>document.getelementbyid("myelement").classname = "myclass"; </code></pre><p>(sie können eine durch leerzeichen getrennte liste verwenden, um mehrere klassen anzuwenden.)</p><h3>so fügen sie einem element eine zusätzliche klasse hinzu:</h3><p>um einem element eine klasse hinzuzufügen, ohne vorhandene werte zu entfernen/zu beeinflussen, fügen sie ein leerzeichen und den neuen klassennamen wie folgt hinzu:</p><pre><code>document.getelementbyid("myelement").classname += " myclass"; </code></pre><h3>so entfernen sie eine klasse aus einem element:</h3><p>um eine einzelne klasse zu einem element zu entfernen, ohne andere potenzielle klassen zu beeinflussen, ist ein einfacher regex-ersetzen erforderlich:</p><pre><code>document.getelementbyid("myelement").classname = document.getelementbyid("myelement").classname.replace ( /(?:^|\s)myclass(?!\s)/g , '' ) /* code wrapped for readability - above is all one statement */ </code></pre><p>eine erklärung dieser regex lautet wie folgt:</p><pre><code>(?:^|\s) # match the start of the string, or any single whitespace character myclass # the literal text for the classname to remove (?!\s) # negative lookahead to verify the above is the whole classname # ensures there is no non-space character following # (i.e. must be end of string or a space) </code></pre><p>das flag <code>g</code> weist das ersetzen an, nach bedarf zu wiederholen, falls der klassenname mehrmals hinzugefügt wurde.</p><h3>so prüfen sie, ob eine klasse bereits auf ein element angewendet wurde:</h3><p>der gleiche reguläre ausdruck, der oben zum entfernen einer klasse verwendet wurde, kann auch zur überprüfung verwendet werden, ob eine bestimmte klasse vorhanden ist:</p><pre><code>if ( document.getelementbyid("myelement").classname.match(/(?:^|\s)myclass(?!\s)/) ) </code></pre><p><br/></p><h3>zuweisen dieser aktionen zu onclick-ereignissen:</h3><p>es ist zwar möglich, javascript direkt in die html-ereignisattribute (z. b. <code>onclick="this.classname+=' myclass'"</code>) zu schreiben, dies wird jedoch nicht empfohlen. insbesondere bei größeren anwendungen wird durch die trennung von html-markup von javascript-interaktionslogik ein wartungsfähigerer code erzielt.</p><p>der erste schritt dazu ist das erstellen einer funktion und das aufrufen der funktion im onclick-attribut. beispiel:</p><pre><code>&lt;script type="text/javascript"&gt; function changeclass(){ // code examples from above } &lt;/script&gt; ... &lt;button onclick="changeclass()"&gt;my button&lt;/button&gt; </code></pre><p><sub><em>(es ist nicht erforderlich, dass dieser code in skript-tags enthalten ist. dies ist lediglich der kürze halber als beispiel gedacht. das einschließen von javascript in eine andere datei ist möglicherweise geeigneter.)</em></sub></p><p>der zweite schritt besteht darin, das onclick-ereignis aus dem html-code in javascript zu verschieben, beispielsweise mit <a href="https://developer.mozilla.org/en-us/docs/dom/element.addeventlistener">addeventlistener</a> </p><pre><code>&lt;script type="text/javascript"&gt; function changeclass(){ // code examples from above } window.onload = function(){ document.getelementbyid("myelement").addeventlistener( 'click', changeclass); } &lt;/script&gt; ... &lt;button id="myelement"&gt;my button&lt;/button&gt; </code></pre><p>(beachten sie, dass der window.onload-teil erforderlich ist, damit der inhalt dieser funktion <em>ausgeführt wird, nachdem der html-code</em> vollständig geladen wurde. andernfalls ist das myelement möglicherweise nicht vorhanden, wenn der javascript-code aufgerufen wird, sodass die zeile fehlschlägt .)</p><p><br/></p><h2>javascript frameworks und bibliotheken</h2><p>der obige code ist alles in standard-javascript enthalten. es ist jedoch üblich, entweder ein framework oder eine bibliothek zu verwenden, um allgemeine aufgaben zu vereinfachen und von behobenen fehlern und edge-fällen zu profitieren, an die sie beim schreiben des codes nicht denken.</p><p>während einige leute es für übertrieben halten, ein ~ 50 kb-framework für das einfache ändern einer klasse hinzuzufügen, ist die überlegung, wenn sie umfangreiche javascript-arbeiten ausführen oder etwas, das ungewöhnliches cross-browser-verhalten hat, eine überlegung wert.</p><p><em>(in groben zügen handelt es sich bei einer bibliothek um eine reihe von werkzeugen, die für eine bestimmte aufgabe entwickelt wurden, während ein framework im allgemeinen mehrere bibliotheken enthält und eine reihe von aufgaben ausführt.)</em></p><p>die obigen beispiele wurden im folgenden mit <a href="http://jquery.com">jquery</a> wiedergegeben, wahrscheinlich der am häufigsten verwendeten javascript-bibliothek (obwohl es auch andere gibt, die es zu untersuchen gilt).</p><p>(beachten sie, dass <code>$</code> hier das jquery-objekt ist.)</p><h3>klassen mit jquery ändern:</h3><pre><code>$('#myelement').addclass('myclass'); $('#myelement').removeclass('myclass'); if ( $('#myelement').hasclass('myclass') ) </code></pre><p>darüber hinaus bietet jquery eine verknüpfung zum hinzufügen einer klasse, wenn sie nicht angewendet wird, oder zum entfernen einer klasse, die folgendes ausführt:</p><pre><code>$('#myelement').toggleclass('myclass'); </code></pre><p><br/></p><h3>zuweisen einer funktion zu einem klickereignis mit jquery:</h3><pre><code>$('#myelement').click(changeclass); </code></pre><p>oder, ohne eine id zu benötigen:</p><pre><code>$(':button:contains(my button)').click(changeclass); </code></pre><p><br/></p> <p>dies kann eine paginierung sein oder auch nicht, aber hier ist, wie ich paginierung in meiner web-app mache:</p><pre><code>|&lt; first, &lt;&lt; previous, page [5] of 12, next &gt;&gt;, last &gt;| </code></pre><p>die äußeren vier optionen sind links, während die <code>page [5] of 12</code> ist ein formular mit dem [5] als eingabefeld. für benutzer mit aktiviertem javascript verstecke ich die schaltfläche "senden" und sende das formular beim ereignis "unfokus" oder drücke den tastendruck. der benutzer hat die option, wie viele zeilen er anzeigen möchte, die er aus einem dropdown-menü auswählen kann: 10, 20, 50, 100, alle. zusätzlich zur paginierung biete ich auch das sortieren und filtern der ergebnisse an, obwohl dies möglicherweise nicht in jeder situation sinnvoll ist.</p><p><strong>bearbeiten</strong>:</p><p>hier ist ein ausschnitt aus einem modell unserer web-app, um ihnen eine bessere vorstellung zu geben. in dieser version wurden die wörter in den schaltflächen weggelassen, werden jedoch nach einer leichten verzögerung als tooltip beim hover angezeigt. möglicherweise stellen sie jedoch fest, dass das beibehalten der wörter zu einer höheren benutzerfreundlichkeit führt.</p><p><img src="https://i.stack.imgur.com/vzbu0.png" alt="virtuosi media&#39;s pagination example"></p><p>ein paar andere dinge, auf die sie hinweisen sollten:</p><ul> <li>die schaltflächen "erste" und "vorherige" wurden deaktiviert, da es sich um die erste seite handelt.</li> <li>das blau zeigt aktive schaltflächen an (ich muss dieses spezielle thema durch eine farbprüfung ausführen, um sicherzustellen, dass farbenblinde benutzer einen unterschied feststellen können).</li> <li>die tasten bleiben immer erhalten, auch wenn sie deaktiviert sind. dies gibt der schnittstelle konsistenz.</li> <li>aufgrund der skalierung habe ich ein eingabefeld anstelle eines dropdown-auswahlfelds ausgewählt. wenn sie 3000 seiten haben, möchten sie nicht nach unten scrollen, um eine seite zu finden</li> <li>die paginierung ist in einer singulären visuellen komponente gruppiert, um ähnlichkeit im zweck anzuzeigen.</li> </ul> <h2>aufgrund der empfehlungen in den kommentaren habe ich begonnen, <a href="http://tools.tortoisesvn.net/grepwin.html">grepwin</a> zu verwenden, und es ist fantastisch und <em> kostenlos</em>.</h2><hr><p>(ich bin immer noch ein fan von <a href="http://www.powergrep.com/">powergrep</a> , aber ich benutze es nicht mehr.)</p><p>ich weiß, dass sie es bereits erwähnt haben, aber powergrep ist <strong> fantastisch </strong>.</p><p>einige meiner lieblingsfunktionen sind:</p><ul> <li>klicken sie mit der rechten maustaste auf einen ordner, um powergrep darauf auszuführen</li> <li>verwenden sie reguläre ausdrücke oder wörtlichen text</li> <li>geben sie platzhalter für dateien an, die ein- und ausgeschlossen werden sollen</li> <li>suchen &amp; ersetzen</li> <li>der vorschaumodus ist gut, da sie sicherstellen können, dass sie das ersetzen, was sie beabsichtigen.</li> </ul><p>jetzt ist mir klar, dass die anderen grep-tools all das tun können. es ist nur so, dass powergrep alle funktionen in einer sehr benutzerfreundlichen benutzeroberfläche zusammenfasst.</p><p><strong> <em> von den gleichen wundervollen leuten, die sie mitgebracht haben <a href="http://en.wikipedia.org/wiki/regexbuddy">regexbuddy</a> und denen ich nichts mehr zu tun habe, als ihre sachen zu lieben.</em> </strong> (es sollte beachtet werden, dass regexbuddy eine basisversion von grep (für windows) selbst enthält und viel weniger kostet als powergrep.)</p><hr><h2>zusätzliche lösungen</h2><h3>vorhandene windows-befehle</h3><ul> <li> <a href="http://ss64.com/nt/findstr.html"> findstr </a> </li> <li> <a href="https://technet.microsoft.com/en-us/library/hh849903.aspx">auswahlzeichenfolge</a> in powershell</li> </ul><h3>linux-befehlsimplementierungen unter windows</h3><ul> <li> <a href="http://en.wikipedia.org/wiki/cygwin">cygwin</a> </li> <li> <a href="https://github.com/dthree/cash">bargeld</a> </li> </ul><h3>grep-tools mit grafischer oberfläche</h3><ul> <li> <a href="http://astrogrep.sourceforge.net/screenshots/">astrogrep</a> </li> <li> <a href="https://www.baremetalsoft.com/baregrep/">baregrep</a> </li> <li> <a href="http://stefanstools.sourceforge.net/grepwin.html">grepwin</a> </li> </ul><h3>zusätzliche grep-tools</h3><ul> <li> <a href="http://code.google.com/p/dngrep/">dngrep</a> </li> </ul> <p>die standardmethode für die angabe des objekttyps ist entweder <a href="http://search.cpan.org/perldoc?perlfunc#ref"><code>ref</code></a> oder <a href="http://search.cpan.org/perldoc?scalar::util"><code>scalar::util</code></a> <code>::blessed</code>. wenn sie<em> wissen </em>das objekt gesegnet ist, geben sie dieselbe information zurück. </p><pre><code>my $class1 = blessed( $obj ); my $class2 = ref $obj; </code></pre><p><code>ref</code> gibt jedoch auch 'hash' für nicht gesegnete hashes zurück, während <code>blessed</code> dieses spiel ablehnt. </p><p>für eine liste von methoden ist es für den gesegneten zeigerstil eines perl-objekts einfach, eine davon selbst zu codieren. der folgende code funktioniert ziemlich gut für mich. es gibt die namen der funktionen (diejenigen, die den &quot;code-slot&quot; des angegebenen namens annehmen) zurück, die dem paket zugeordnet sind, das sie definiert. </p><pre><code>sub class\_methods { use class::isa; my $obj = shift; return unless ref( $obj ); my %meth\_names; foreach my $anc ( class::isa::self\_and\_super\_path( ref $obj ), 'universal' ) { my $stash = \%{"$anc\::"}; my @funcs = grep { m/^[\_\p{alpha}]/ # begins with \_ or alpha &amp;&amp; !exists $meth\_names{$\_} # no clobbering &amp;&amp; defined *{$stash-&gt;{$\_}}{code} # has a filled code slot } keys %$stash ; # assign to the "hash slice", keyed by all the entries in @funcs # the value of $anc repeated as many times as elements in @funcs. @meth\_names{@funcs} = ( $anc ) x @funcs; } return %meth\_names; } </code></pre><ul> <li><p>dies funktioniert auch für relativ komplexe objekte, aber wenn das besitzende paket eine menge generierten codes enthält, ist es nicht besonders hilfreich zu wissen, in welchem ​​paket die generatoren den code-pointer stecken. es wird mehr bedeuten, welches paket zu finden ist generiert den code. </p></li> <li><p>ist dies der fall, erhalten sie<em> might </em>den code aus der ausführung ihres codes, einschließlich <a href="http://search.cpan.org/perldoc?data::dumper"><code>data::dumper</code></a> und setzen von <code>$data::dumper::deparse</code> auf 1 wie folgt: (<code>local $data::dumper::deparse = 1;</code>) und dann den code-zeiger wie folgt: <code>say dumper( $code\_ref );</code></p></li> <li><p>es<em> won't </em>funktioniert für gültige methoden, die noch mit einer beliebigen <code>autoload</code>-methode erstellt werden müssen. wenn sie diese in der liste sehen, macht das objekt möglicherweise mehr, aber was es alles tut, wissen sie nicht.</p></li> <li><p>die &quot;basisklasse&quot; <code>universal</code> ist enthalten, da diese klasse verhalten enthält, das vom objekt verwendet werden kann. </p></li> </ul><p>viel glück.</p> eine individuell entwickelte webanwendung ist oft preiswerter als eine standardsoftware. ihr vorteil besteht darin, dass sie nur die kosten für die einmalige entwicklung der software investieren müssen. da sie zum eigentümer der software werden, entstehen keine weiteren lizenzkosten und zwar unabhängig von der benutzeranzahl und der dauer der nutzung. weitere informationen finden sie in unserem wiki-beitrag über die kosten einer individualsoftware (<https://www.trinidat.de/software-wiki/individualsoftware-kosten/>). Parameter von Lambda-Ausdrücken verwenden keine auf Namen basierende Gleichheit, sie verwenden Referenzgleichheit. In Ihrem Ausdruck haben Sie also zwei völlig verschiedene Parameter namens `s` , einer ist definiert, wird aber nicht verwendet, der andere wird verwendet, aber nicht definiert. 

 Also, im Grunde ist Ihr Ausdruck etwas wie `s1 => s2 == "test"` , weshalb er nicht kompiliert werden kann. Die einfachste Lösung wäre, denselben Parameter zu verwenden, den der ursprüngliche Ausdruck verwendet: 


```
LambdaExpression lambda = Expression.Lambda(equal.Body, equal.Parameters.Single());

```
  Wenn Sie wirklich Ihren eigenen Parameter verwenden möchten, müssten Sie alle Instanzen des ursprünglichen Parameters im Lambda-Body durch Ihren neuen Parameter ersetzen. Der beste Weg dies zu tun, ist [`ExpressionVisitor`](http://msdn.microsoft.com/en-us/library/system.linq.expressions.expressionvisitor.aspx) zu verwenden.