Ich verwende Visual Studio 2010 + Resharper und es wird eine Warnung zum folgenden Code angezeigt :
if (rect.Contains(point))
{
...
}
rect
ist ein readonly Rectangle
Feld und Resharper zeigt mir diese Warnung:
"Die unreine Methode wird für ein schreibgeschütztes Feld vom Werttyp aufgerufen."
Was sind unreine Methoden und warum wird mir diese Warnung angezeigt?
Antworten:
Zunächst einmal sind die Antworten von Jon, Michael und Jared im Wesentlichen richtig, aber ich möchte noch ein paar Dinge hinzufügen.
Es ist einfacher, reine Methoden zu charakterisieren. Eine "reine" Methode hat folgende Eigenschaften:
Zum Beispiel
Math.Cos
ist eine reine Methode. Die Ausgabe hängt nur von der Eingabe ab, und die Eingabe wird durch den Aufruf nicht geändert.Eine unreine Methode ist eine Methode, die nicht rein ist.
Es gibt zwei, die mir in den Sinn kommen. Das erste ist das, auf das Jon, Michael und Jared hingewiesen haben, und das ist das, vor dem Resharper Sie warnt. Wenn Sie eine Methode für eine Struktur aufrufen, übergeben wir immer einen Verweis auf die Variable, die der Empfänger ist, falls die Methode die Variable mutieren möchte.
Was ist, wenn Sie eine solche Methode für einen Wert und nicht für eine Variable aufrufen? In diesem Fall erstellen wir eine temporäre Variable, kopieren den Wert hinein und übergeben einen Verweis auf die Variable.
Eine schreibgeschützte Variable wird als Wert betrachtet, da sie außerhalb des Konstruktors nicht mutiert werden kann. Wir kopieren die Variable also in eine andere Variable, und die unreine Methode mutiert möglicherweise die Kopie, wenn Sie beabsichtigen, die Variable zu mutieren.
Das ist die Gefahr, eine schreibgeschützte Struktur als Empfänger zu übergeben . Es besteht auch die Gefahr, dass eine Struktur übergeben wird, die ein schreibgeschütztes Feld enthält. Eine Struktur, die ein schreibgeschütztes Feld enthält, ist eine gängige Praxis, aber es wird im Wesentlichen ein Scheck ausgestellt, dass das Typsystem nicht über die Mittel verfügt, um Bargeld zu erhalten. Die "Nur-Lese-Fähigkeit" einer bestimmten Variablen wird vom Eigentümer des Speichers bestimmt. Eine Instanz eines Referenztyps "besitzt" ihren eigenen Speicher, eine Instanz eines Werttyps jedoch nicht!
Man glaubt, dass
this.x
sich das nicht ändern wird, weil x ein schreibgeschütztes Feld undBadness
kein Konstruktor ist. Aber...... zeigt deutlich die Falschheit davon.
this
unds
verweisen auf dieselbe Variable, und diese Variable ist nicht schreibgeschützt!quelle
struct Id {
private readonly int _id;
public Id(int id) { _id = id; }
public int ToInt() => _id;
}
Warum ist ToInt unrein?return
. Auf dieser Grundlage schätze ich, dass das einzige Kriterium darin besteht, ob die Methode das[Pure]
Attribut hat oder nicht .rect
. Wollen wir damit sagen, dass eine Kopie vonrect
anContains
method übergeben wird?Eine unreine Methode ist eine, bei der nicht garantiert wird, dass der Wert unverändert bleibt.
In .NET 4 können Sie Methoden und Typen mit dekorieren
[Pure]
, um sie als rein zu deklarieren, und R # wird dies zur Kenntnis nehmen. Leider können Sie es nicht auf andere Mitglieder anwenden und R # nicht davon überzeugen, dass ein Typ / Mitglied meines Wissens in einem .NET 3.5-Projekt rein ist. (Das beißt mich die ganze Zeit in der Noda- Zeit.)Die Idee ist, dass wenn Sie eine Methode aufrufen, die eine Variable mutiert, diese aber in einem schreibgeschützten Feld aufruft, sie wahrscheinlich nicht das tut, was Sie wollen, sodass R # Sie davor warnt. Beispielsweise:
Dies wäre eine wirklich nützliche Warnung, wenn jede Methode, die tatsächlich rein war, auf diese Weise deklariert würde. Leider nicht, daher gibt es viele Fehlalarme :(
quelle
JetBrains.Annotations.PureAttribute
anstelle von verwendenSystem.Diagnostics.Contracts.PureAttribute
, sie haben dieselbe Bedeutung für die ReSharper-Code-Analyse und sollten unter .NET 3.5, .NET 4 oder Silverlight gleichermaßen funktionieren. Sie können Assemblys, die Sie nicht besitzen, auch extern mit XML-Dateien versehen (sehen Sie sich das Verzeichnis ExternalAnnotations im ReSharper-Bin-Pfad an). Dies kann sehr nützlich sein!System.Diagnostics.Contracts.PureAttribute
diese Warnung in R # 8.2 nicht unterdrückt wurdeJetBrains.Annotations.PureAttribute
. Die beiden Attribute haben auch unterschiedliche Beschreibungen: Das VertragsattributPure
impliziert "Ergebnis hängt nur von Parametern ab", während JetBrainsPure
impliziert "keine sichtbaren Statusänderungen verursacht", ohne den Objektstatus auszuschließen, der zur Berechnung des Ergebnisses verwendet wird. (Aber immer noch Verträge, diePure
nicht die gleiche Wirkung auf diese Warnung haben, sind wahrscheinlich ein Fehler.)Die kurze Antwort lautet, dass dies ein falsches Positiv ist und Sie die Warnung ignorieren können.
Die längere Antwort lautet, dass beim Zugriff auf einen schreibgeschützten Werttyp eine Kopie davon erstellt wird, sodass Änderungen am Wert, die von einer Methode vorgenommen werden, nur die Kopie betreffen. ReSharper erkennt nicht, dass dies
Contains
eine reine Methode ist (was bedeutet, dass es keine Nebenwirkungen hat). Eric Lippert spricht hier darüber: Mutating Readonly Structsquelle
private readonly SpinLock _spinLock = new SpinLock();
- Eine solche Sperre wäre völlig nutzlos (da der schreibgeschützte Modifikator jedes Mal, wenn eine Enter-Methode aufgerufen wird, eine On-the-Fly-Kopie erstellt)Es klingt so, als ob Reshaprer glaubt, dass die Methode
Contains
denrect
Wert mutieren kann. Darect
eine istreadonly struct
der Compiler C # macht defensive Kopien des Wertes des Verfahrens von Mutieren eines verhindernreadonly
Feld. Im Wesentlichen sieht der endgültige Code so ausResharper warnt Sie hier, dass
Contains
es zurect
einer Mutation kommen kann, die sofort verloren geht, weil es vorübergehend passiert ist.quelle
Eine unreine Methode ist eine Methode, die Nebenwirkungen haben kann. In diesem Fall scheint Resharper zu glauben, dass sich dies ändern könnte
rect
. Wahrscheinlich nicht, aber die Beweiskette ist unterbrochen.quelle