Ich habe also eine PropertyBag-Klasse, die INotifyPropertyChanged implementieren soll. Um diesen Code so sauber wie möglich zu machen und Benutzerfehler zu vermeiden, verwende ich den Stack, um den Namen der Eigenschaft zu erhalten. Sehen Sie, wenn der Name der Eigenschaft nicht exakt mit der tatsächlichen Eigenschaft übereinstimmt, dann haben Sie einen Fehler und ich versuche, mich davor zu schützen.
Also, hier ist ein Beispiel für die Verwendung der Klasse:
%Vor%Der wichtige Code für die Basis-PropertyBag ist hier:
%Vor%Nun, da Sie meinen Code gesehen haben, kann ich Ihnen das Problem sagen ... In einigen Fällen wurde unter Release Build der "Foo" Setter im "MyData" -Konstruktor für Inline als SetProperty optimiert (- 1). Leider scheitert diese Inline-Optimierung an meiner SetProperty-Methode, weil ich sie nicht mehr von einer Eigenschaft aus anrufe! SCHEITERN. Es scheint, dass ich mich auf diese Weise nicht auf den StackTrace verlassen kann.
Kann jemand A: Finden Sie einen besseren Weg, dies zu tun, aber vermeiden Sie immer noch "Foo" zu GetProperty und SetProperty? B: Finden Sie heraus, wie der Compiler in diesem Fall nicht optimieren soll?
Hier ist der Stack langsam und unnötig; Ich würde einfach verwenden:
%Vor%(Hinweis: Ich habe viel mit benutzerdefinierten Eigenschaftsmodellen gearbeitet; ich weiß, dass das gut funktioniert ...)
Eine andere Alternative ist ein Objektschlüssel (Referenzvergleich zum Vergleichen verwenden) - viele ComponentModel
funktionieren auf diese Weise, wie auch einige der Eigenschaften in WF / WPF:
Natürlich könnten Sie einen Typ für die Schlüssel deklarieren (mit einer Name
-Eigenschaft) und folgendes verwenden:
usw .; Um jedoch die Frage zu beantworten: Markieren Sie es (aber nicht dies tun) mit:
%Vor%oder
%Vor% oder
Die Verwendung des Stapels ist keine gute Idee. Sie verlassen sich auf die interne Implementierung des Compilers, um Ihren Eigenschaftenbeutel mit den Spracheigenschaften künstlich zu verknüpfen.
MethodImpl
hinzuzufügen, macht die Verwendung Ihres Eigentumsbeutels für andere Entwickler nicht transparent. MethodImpl
hat, garantiert nichts, dass es das erste Bild auf dem Aufrufstapel ist. Es ist möglich, dass die Assembly instrumentiert oder modifiziert wurde, um Anrufe zwischen der tatsächlichen Eigenschaft und dem Anruf in Ihre Eigentumstasche einzufügen. (Think Aspect Programmierung) '_get'
und '_set'
Sie sollten wirklich Ihre Property-Bag-Accessoren implementieren, um einen Parameter zur Identifizierung der Eigenschaft zu verwenden - entweder einen String-Namen (wie Hastable) oder ein Objekt (wie die WPF-Abhängigkeits-Eigenschaft bag)
Probieren Sie das neue [CallerMemberName] -Attribut aus.
Platzieren Sie es auf einen Parameter zu Ihrer Methode ([CallerMemberName] callerName = null) und der Compiler überschreibt alle Aufrufe Ihrer Methode, um den Namen des Aufrufers automatisch zu übergeben (Ihre Aufrufe übergeben den Parameter überhaupt nicht).
Es beseitigt keine Optimierungen und ist viel schneller als Lambdas oder Reflektion oder Stacks und arbeitet im Release-Modus.
P.S. Wenn CallerMemberNameAttribute in Ihrer Version des Frameworks nicht vorhanden ist, definieren Sie es einfach (leer). Es ist ein Sprachfeature, kein Framework-Feature. Wenn der Compiler [CallerMemberNameAttribute] für einen Parameter sieht, funktioniert es einfach.
Sie können versuchen, eine T4-Vorlagendatei zu erstellen, damit Ihre Eigenschaften automatisch mit den richtigen Eigenschaftsnamen für die Methoden GetProperty () und SetProperty () generiert werden können.
T4: Text Template Transformation Toolkit T4-Codegenerierung (Text Template Transformation Toolkit) - Bestgehütetes Visual Studio-Geheimnis
Wenn Sie hartcodierte Zeichenfolgen vermeiden möchten, können Sie Folgendes verwenden:
%Vor%Fügen Sie weitere Sicherheitsüberprüfungen hinzu, so wie Sie es für richtig halten
dann wird die Eigenschaft
%Vor%Sätze ändern sich auf die gleiche Weise.
GetCurrentMethod () durchläuft auch den Stack, tut dies jedoch über einen (internen) nicht verwalteten Aufruf, der auf Stack-Markern basiert, so dass er auch im Release-Modus funktioniert.
Alternativ für eine schnelle Korrektur [MethodImpl] mit MethodImplAttributes.NoOptimization) oder MethodImplAttributes.NoInlining funktioniert auch, wenn auch mit einem Performance-Hit (obwohl Sie den Stack-Frame jedes Mal durchlaufen, wenn dieser Treffer vernachlässigbar ist).
Eine weitere Technik, um eine gewisse Kompilierzeitprüfung durchzuführen, ist:
%Vor%wobei Xxxxx die Klasse ist, in der die Eigenschaft definiert ist. Wenn die statische Natur Probleme verursacht (Threading oder sonstwie ist es möglich, einen Instanzwert zu erstellen).
Ich sollte darauf hinweisen, dass diese Techniken wirklich aus Interessensgründen sind, ich behaupte nicht, dass es sich um gute allgemeine Techniken handelt.
Tags und Links c# stack-trace