Frage Die unreine Methode wird für das schreibgeschützte Feld aufgerufen


Ich benutze Visual Studio 2010 + Nachschärfer und es wird eine Warnung für den folgenden Code angezeigt:

if (rect.Contains(point))
{
    ...
}

rect ist ein readonly Rectangle Feld und Resharper zeigt mir diese Warnung:

"Ungültige Methode wird für schreibgeschütztes Feld vom Werttyp aufgerufen."

Was sind unreine Methoden und warum wird diese Warnung mir gezeigt?


75
2018-03-29 14:29


Ursprung


Antworten:


Zunächst einmal sind Jon, Michael und Jareds Antworten im Wesentlichen richtig, aber ich habe noch ein paar Dinge, die ich ihnen hinzufügen möchte.

Was ist mit einer "unreinen" Methode gemeint?

Es ist einfacher, reine Methoden zu charakterisieren. Eine "reine" Methode hat folgende Eigenschaften:

  • Seine Ausgabe wird gänzlich durch seine Eingabe bestimmt; Seine Ausgabe hängt nicht von externen Faktoren wie der Tageszeit oder den Bits auf Ihrer Festplatte ab. Seine Ausgabe hängt nicht von seiner Geschichte ab; Der Aufruf der Methode mit einem gegebenen Argument zweimal sollte das gleiche Ergebnis liefern.
  • Eine reine Methode produziert keine beobachtbaren Mutationen in der Welt um sie herum. Eine reine Methode kann den privaten Status aus Effizienzgründen mutieren, aber eine reine Methode mutiert ein Feld ihres Arguments nicht.

Beispielsweise, Math.Cos ist eine reine Methode. Seine Ausgabe hängt nur von seiner Eingabe ab, und die Eingabe wird durch den Anruf nicht geändert.

Eine unreine Methode ist eine Methode, die nicht rein ist.

Was sind einige der Gefahren, Readonly-Strukturen zu unreinen Methoden zu übergeben?

Da kommen mir zwei in den Sinn. Der erste ist derjenige, auf den Jon, Michael und Jared hingewiesen haben und über den Resharper dich 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 ändern 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 eine Referenz an die Variable.

Eine schreibgeschützte Variable wird als Wert betrachtet, da sie außerhalb des Konstruktors nicht mutiert werden kann. Daher kopieren wir die Variable in eine andere Variable, und die unreine Methode mutiert möglicherweise die Kopie, wenn Sie beabsichtigen, die Variable zu ändern.

Das ist die Gefahr, eine readonly Struktur als a zu übergeben Empfänger. 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, schreibt aber im Wesentlichen eine Prüfung, dass das Typsystem nicht über die Mittel verfügt, um Geld zu beschaffen. Die "Read-Only-Ness" einer bestimmten Variablen wird vom Eigentümer des Speichers bestimmt. Eine Instanz eines Referenztyps "besitzt" einen eigenen Speicher, aber eine Instanz eines Werttyps nicht!

struct S
{
  private readonly int x;
  public S(int x) { this.x = x; }
  public void Badness(ref S s)
  {
    Console.WriteLine(this.x);   
    s = new S(this.x + 1);
    // This should be the same, right?
    Console.WriteLine(this.x);   
  }
}

Das denkt man this.x wird sich nicht ändern, weil x ein schreibgeschütztes Feld ist und Badness ist kein Konstruktor. Aber...

S s = new S(1);
s.Badness(ref s);

... zeigt deutlich die Falschheit davon. this und s beziehen sich auf die gleiche Variable und Das Variable wird nicht gelesen!


85
2018-03-29 15:32



Eine unreine Methode ist eine Methode, die nicht garantiert, dass der Wert so bleibt, wie er war.

In .NET 4 können Sie Methoden und Typen mit dekorieren [Pure] um sie für rein zu erklären, und R # wird dies bemerken. Leider können Sie es nicht auf die Mitglieder eines anderen Benutzers anwenden, und Sie können R # nicht überzeugen, dass ein Typ / Member in einem .NET 3.5-Projekt rein ist, soweit mir bekannt ist. (Dies beißt mich in Noda Zeit die ganze Zeit.)

Das Idee Wenn Sie eine Methode aufrufen, die eine Variable verändert, aber Sie sie in einem schreibgeschützten Feld aufrufen, ist es wahrscheinlich nicht tun was du willst, also wird R # dich davor warnen. Beispielsweise:

public struct Nasty
{
    public int value;

    public void SetValue()
    {
        value = 10;
    }
}

class Test
{
    static readonly Nasty first;
    static Nasty second;

    static void Main()
    {
        first.SetValue();
        second.SetValue();
        Console.WriteLine(first.value);  // 0
        Console.WriteLine(second.value); // 10
    }
}

Dies wäre eine wirklich nützliche Warnung, wenn jede Methode, die tatsächlich rein war, so erklärt wurde. Leider sind sie nicht, also gibt es viele falsche Positive :(


46
2018-03-29 14:32



Die kurze Antwort ist, dass dies ein falsches positives Ergebnis ist, und Sie können die Warnung ignorieren.

Die längere Antwort lautet, dass beim Zugriff auf einen schreibgeschützten Werttyp a Kopieren davon, dass alle Änderungen an dem von einer Methode gemachten Wert nur die Kopie betreffen. ReSharper merkt das nicht Contains ist eine reine Methode (dh es hat keine Nebenwirkungen). Eric Lippert spricht hier darüber: Mutating Readonly Structs


14
2018-03-29 14:36



Es klingt, als ob Reshaprer die Methode glaubt Contains kann das mutieren rect Wert. weil rect ist ein readonly struct Der C # -Compiler erstellt defensive Kopien des Werts, um zu verhindern, dass die Methode mutiert readonly Feld. Im Wesentlichen sieht der endgültige Code so aus

Rectangle temp = rect;
if (temp.Contains(point)) {
  ...
}

Resharper warnt dich hier Contains kann mutieren rect in einer Weise, die sofort verloren wäre, weil es auf einem temporären geschah.


11
2018-03-29 14:35



Eine unreine Methode ist eine Methode, die Nebenwirkungen haben kann. In diesem Fall scheint Resharper zu denken, dass es sich ändern könnte rect. Es ist wahrscheinlich nicht, aber die Kette der Beweise ist gebrochen.


5
2018-03-29 14:33