Impuro viene chiamato il metodo per readonly campo

Sto usando Visual Studio 2010 + Resharper e mostra un messaggio di avviso sul codice riportato di seguito:

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

rect è un readonly Rectangle campo, e Resharper mi mostra questo avviso:

“Impuro viene chiamato il Metodo per readonly campo di tipo di valore.”

Cosa impura metodi e perché è di questo avviso, di essere mostrato a me?

InformationsquelleAutor Acidic | 2012-03-29

 

5 Replies
  1. 95

    Prima di tutto, Jon, Michael e Jared risposte sono sostanzialmente corretti, ma ho un paio di cose che mi piacerebbe aggiungere a loro.

    Qual è il significato di un “impuro” metodo?

    È più facile per caratterizzare puro metodi. Un “puro” metodo ha le seguenti caratteristiche:

    • La sua uscita è interamente determinata dal suo ingresso; la sua uscita non dipende da fattori esterni come l’ora del giorno o i bit sul disco rigido. La sua uscita non dipende dalla sua storia; chiamando il metodo con un argomento dato due volte dovrebbe dare lo stesso risultato.
    • Un puro metodo non produce osservabili mutazioni nel mondo che la circonda. Un puro metodo può scegliere di mutare privato stato per motivi di funzionalità, ma un puro metodo non, per dire, a mutare in un campo di argomento.

    Per esempio, Math.Cos è un puro metodo. La sua uscita dipende solo dal suo ingresso, e l’ingresso non è cambiato dalla chiamata.

    Un impuro metodo è un metodo che non è puro.

    Quali sono alcuni dei pericoli di passare readonly strutture per impura metodi?

    Ci sono due che mi vengono in mente. Il primo è quello sottolineato da Jon, Michael e Jared, e questo è quello che Resharper è di avviso sull’. Quando si chiama un metodo su una struttura, abbiamo sempre passare un riferimento alla variabile che è il destinatario, nel caso in cui il metodo vuole mutare la variabile.

    Così che cosa se si chiama questo metodo su un valore, piuttosto che una variabile? In questo caso facciamo una variabile temporanea, copia il valore in esso, e passare un riferimento alla variabile.

    Una variabile in sola lettura è considerato un valore, perché non può essere mutato al di fuori del costruttore. Siamo quindi copia la variabile in un’altra variabile, e l’impuro metodo è forse mutando la copia, quando avete intenzione di mutare la variabile.

    Che il pericolo del passaggio di un readonly struct come ricevitore. C’è anche un pericolo di superamento di una struct che contiene un readonly campo. Una struct che contiene un readonly campo è una pratica comune, ma essenzialmente è la scrittura di un assegno che il tipo di sistema non ha i fondi per la cassa; il “read-only-ness” di una particolare variabile è determinato dal proprietario del deposito. Un’istanza di un riferimento di tipo “proprietario”, la sua conservazione, ma un’istanza di un tipo di valore non!

    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);   
      }
    }

    Si pensa che this.x non ha intenzione di cambiare perché x è un readonly campo e Badness non è un costruttore. Ma…

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

    … chiaramente dimostra la falsità di che. this e s fare riferimento alla stessa variabile, e che variabile non è in sola lettura!

    • Fiera abbastanza, ma vi prego di considerare questo codice: struct Id { private readonly int _id; public Id(int id) { _id = id; } public int ToInt() => _id; } Perché è ToInt “impura”?
    • È la tua domanda in realtà “perché Resharper considera impuri?” Se la tua domanda quindi trovare qualcuno che lavora su R# e chiedere a loro!
    • Resharper darà a questo avviso, anche se il metodo è nulla e non fa nulla se non return. Sulla base di che, sto cercando di indovinare che l’unico criterio è se o non il metodo ha il [Pure] attributo.
  2. 50

    Un impuro metodo è uno che non è garantita per lasciare il valore era.

    In .Rete 4 si possono decorare i metodi e i tipi con [Pure] dichiarare di essere puro, e R# prenderà atto di questo. Purtroppo, non è possibile applicare a qualcun altro i membri, e non riesci a convincere R# che un tipo/membro è pure in un .NET 3.5 progetto per quanto ne sono a conoscenza. (Questo punture di me in Noda Tempo tutto il tempo).

    Il idea è che se si chiama un metodo che muta in una variabile, ma si chiamano in un campo di sola lettura, è probabilmente non fare quello che vuoi, in modo da R# avverte di questo. Per esempio:

    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
        }
    }

    Questo sarebbe davvero utile avvertenza se ogni metodo che in realtà era pure stato dichiarato che modo. Purtroppo non lo sono, quindi ci sono un sacco di falsi positivi 🙁

    • In modo che significa che un impuro metodo è possibile modificare i campi sottostanti della mutevole valuetype passato?
    • Non è l’argomento del valore – anche un impuro metodo può farlo – ma il valore è call su. (Vedi il mio esempio, in cui il metodo non hanno parametri.)
    • Questo significa che qualsiasi tipo di valore che readonly diventa immutabile?
    • È possibile utilizzare JetBrains.Annotations.PureAttribute invece di System.Diagnostics.Contracts.PureAttribute, hanno lo stesso significato per ReSharper analisi del codice e dovrebbe funzionare su .NET 3.5, .NET 4 o Silverlight. Si può anche esternamente annotare le assemblee non è proprio tramite file XML (guarda il ExternalAnnotations directory ReSharper bin percorso), può essere davvero molto utile!
    • Mi piacerebbe essere davvero riluttanti a iniziare ad aggiungere strumento annotazioni specifiche – soprattutto per un progetto open source. Buon per conoscere opzioni, ma…
    • Con voto positivo per la concisa risposta e un grande esempio. Grazie. 🙂
    • In realtà ho scoperto che System.Diagnostics.Contracts.PureAttribute non sopprimere questo avviso in R# 8.2, mentre JetBrains.Annotations.PureAttribute fatto. I due attributi hanno anche diverse descrizioni: I contratti Pure attributo implica “il risultato dipende solo dai parametri”, mentre il JetBrains Pure implica “non causano cambiamenti di stato” senza escludere lo stato dell’oggetto utilizzato per calcolare il risultato. (Ma ancora contratti Pure non avere lo stesso effetto su di questo avvertimento probabilmente è un bug.)
    • Io non sono sicuro che i contratti di documentazione a cui ti stai riferendo, ma msdn.microsoft.com/en-us/library/… è descritto come “Indica che un tipo o di un metodo che è puro, quello che è, non rendere visibili i cambiamenti di stato.” – Non vedo nulla di risultato solo in funzione dei parametri.
    • A prescindere dal ReSharper avvisi, qualsiasi attributo influenzano il compilatore ed evitare difensiva copia? Per favore, non dirmi che il compilatore non è abbastanza intelligente per fare questo comunque – purtroppo, questo non è vero, anche per i casi più semplici. Imparato nel modo più duro.
    • Il compilatore sicuramente non usa il JetBrains attributi. Ma ora, in C# 7 è possibile creare un readonly struct, a che punto è non evitare difensiva copia. Specificato tramite un attributo di troppo (IsReadOnlyAttribute) quindi sì, ci sono attributi che cambiare ciò che il compilatore. C# 8 permette anche readonly dichiarazioni di metodo; non ho ancora controllato se per evitare la copia, ma mi auguro che fa.
    • Grazie @JonSkeet per il puntamento IsReadOnlyAttribute docs.microsoft.com/en-us/dotnet/api/…, che è un’alternativa interessante per readonly struct. Vorrei aggiungere che la parola chiave è associato a C#7.2, mentre l’attributo è disponibile solo per netstandard2.1.

  3. 15

    La risposta breve è che questo è un falso positivo, ed è possibile ignorare il messaggio di avviso.

    La risposta è più che l’accesso a un valore di sola lettura tipo crea un copia di esso, in modo che eventuali modifiche al valore fatta da un metodo dovrebbe interessare solo la copia. ReSharper non si rende conto che Contains è un puro metodo (che significa che non ha effetti collaterali). Eric Lippert ne parla qui: Mutando Readonly Strutture

    • Si prega di non ignorare questo avviso finché non è completamente capito!!!! Un buon esempio di questo può essere sicuro è questo costrutto: private readonly SpinLock _spinLock = new SpinLock(); – ad un blocco sarebbe completamente inutile (dato che readonly modificatore di on-the-fly copia creata ogni volta che Invio, viene chiamato il metodo su di esso)
  4. 11

    Sembra Reshaprer ritiene che il metodo Contains in grado di mutare il rect valore. Perché rect è un readonly struct il compilatore C# ti difensiva copie di valore per evitare che il metodo dalla mutazione di un readonly campo. Essenzialmente la finale codice simile a questo

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

    Resharper avviso è qui che Contains può mutare rect in modo tale da essere immediatamente perso perché è successo temporaneo.

    • In modo che non impatto ogni logica eseguita nel metodo, solo evitare che mutando il valore che è stato chiamato, giusto?
    • questo è corretto
  5. 5

    Un Impuro metodo è un metodo che potrebbe avere effetti collaterali. In questo caso, Resharper sembra pensare che potrebbe cambiare rect. Probabilmente no, ma la catena di prove è rotto.

Lascia un commento