87 votes

La méthode impure est appelée pour le champ en lecture seule

J'utilise Visual Studio 2010 + Resharper et il affiche un avertissement sur le code suivant:

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

rect est un champ readonly Rectangle , et Resharper me montre cet avertissement:

"Méthode impure est appelée pour le champ en lecture seule du type valeur."

Quelles sont les méthodes impures et pourquoi cet avertissement m'est-il montré?

96voto

Eric Lippert Points 300275

Tout d'abord, Jon, Michael et Jared réponses sont essentiellement correct mais j'ai un peu plus de choses que je voudrais ajouter.

Qu'entend-on par "impurs" méthode?

Il est plus facile de caractériser pur méthodes. Un "pur" méthode possède les caractéristiques suivantes:

  • Sa sortie est entièrement déterminée par son entrée, sa sortie ne dépend pas d'externalités comme le moment de la journée ou les bits sur votre disque dur. Sa sortie ne dépend pas de son histoire; à l'appel de la méthode, avec un argument donné deux fois devraient donner le même résultat.
  • Une pure méthode ne produit pas de mutations observables dans le monde autour d'elle. Une pure méthode peut choisir de muter privé de l'état pour des raisons d'efficacité, mais une pure méthode n'est pas, disons, de muter un champ de son argument.

Par exemple, Math.Cos est une méthode pure. Sa sortie ne dépend que de son entrée, et l'entrée n'est pas modifiée par l'appel.

Un impur est une méthode qui n'est pas pur.

Quels sont les dangers du passage readonly les structures de l'impur méthodes?

Il y a deux qui me viennent à l'esprit. Le premier est celui que l'a souligné Jon, Michael et Jared, et c'est celui que Resharper est pour vous avertir au sujet. Lorsque vous appelez une méthode sur un struct, on passe toujours une référence à la variable qui est le récepteur, dans le cas de la méthode tient à la mutation de l'variable.

Alors que faire si vous appelez cette méthode sur une valeur, plutôt qu'une variable? Dans ce cas, nous faisons une variable temporaire, copie de la valeur, et de passer une référence à la variable.

Une lecture seule variable est considérée comme une valeur, car il ne peut pas être muté à l'extérieur du constructeur. Nous sommes donc la copie de la variable à une autre variable, et de l'impur méthode est peut-être la mutation de la copie, lorsque vous avez l'intention à muter la variable.

C'est le danger de passage d'un readonly struct comme un récepteur. Il y a également un risque de passage d'une structure qui contient un champ en lecture seule. Une structure qui contient un champ en lecture seule est une pratique courante, mais c'est surtout l'écriture d'un chèque que le type de système de ne pas avoir les fonds à la trésorerie; le "read-only-ness" d'une variable donnée est déterminé par le propriétaire de l'espace de stockage. Une instance d'un type de référence "propriétaire" de son propre espace de stockage, mais une instance d'un type de valeur ne fait pas!

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

On pense que l' this.x ne va pas changer parce que x est un champ en lecture seule et Badness n'est pas un constructeur. Mais...

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

... montre clairement la fausseté de cette. this et s reportez-vous à la même variable, et que la variable n'est pas en lecture seule!

51voto

Jon Skeet Points 692016

Un impur méthode est celle qui n'est pas garanti à partir de la valeur comme il était.

Dans .NET 4 vous pouvez décorer les méthodes et les types avec [Pure] à déclarer être pur, et R# prendra la notification de la présente. Malheureusement, vous ne pouvez pas demander à quelqu'un d'autre membres, et vous ne pouvez pas convaincre R# qu'un type ou d'un membre est pur dans une .NET 3.5 projet pour autant que je suis au courant. (Ce qui me mord dans Noda Temps tout le temps.)

L' idée est que si vous appelez une méthode qui transforme une variable, mais vous appelez ça sur un champ en lecture seule, ce n'est probablement pas ce que vous voulez, donc R# vous avertir à ce sujet. Par exemple:

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

15voto

Michael Liu Points 15764

La réponse courte est que c'est un faux positif, et vous pouvez ignorer l'avertissement.

Plus la réponse est que l'accès à une valeur en lecture seule type crée une copie de lui, de sorte que toute modification de la valeur rendue par une méthode affecte uniquement la copie. ReSharper ne se rend pas compte qu' Contains est une méthode pure (ce qui signifie qu'il n'a pas d'effets secondaires). Eric Lippert en parle ici: la Mutation Readonly Structs

11voto

JaredPar Points 333733

Il sonne comme Reshaprer estime que la méthode Contains peut muter l' rect de la valeur. Parce qu' rect est readonly struct le compilateur C# fait défensive des copies de la valeur afin d'empêcher la méthode de la mutation d'un readonly champ. Essentiellement la version finale du code ressemble à ceci

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

Resharper est d'avertissement ici qu' Contains peut muter rect de manière à être immédiatement perdu parce que c'est arrivé sur un temporaire.

5voto

Henk Holterman Points 153608

Une méthode impure est une méthode qui pourrait avoir des effets secondaires. Dans ce cas, Resharper semble penser que cela pourrait changer rect . Ce n'est probablement pas le cas, mais la chaîne de preuves est brisée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X