Em primeiro lugar, as respostas de Jon, Michael e Jared estão essencialmente corretas, mas tenho mais algumas coisas que gostaria de acrescentar a elas.
O que se entende por método "impuro"?
É mais fácil caracterizar métodos puros. Um método "puro" tem as seguintes características:
- Sua saída é inteiramente determinada por sua entrada; sua saída não depende de externalidades como a hora do dia ou os bits em seu disco rígido. Sua saída não depende de seu histórico; chamar o método com um determinado argumento duas vezes deve dar o mesmo resultado.
- Um método puro não produz mutações observáveis no mundo ao seu redor. Um método puro pode escolher transformar o estado privado por uma questão de eficiência, mas um método puro não muda, digamos, um campo de seu argumento.
Por exemplo, Math.Cosé um método puro. Sua saída depende apenas de sua entrada, e a entrada não é alterada pela chamada.
Um método impuro é um método que não é puro.
Quais são alguns dos perigos de passar structs somente leitura para métodos impuros?
Existem dois que vêm à mente. O primeiro é aquele apontado por Jon, Michael e Jared, e é sobre este que Resharper está avisando. Quando você chama um método em uma estrutura, sempre passamos uma referência para a variável que é o receptor, caso o método deseje transformar a variável.
E daí se você chamar esse método em um valor, em vez de em uma variável? Nesse caso, criamos uma variável temporária, copiamos o valor para ela e passamos uma referência à variável.
Uma variável somente leitura é considerada um valor, porque não pode sofrer mutação fora do construtor. Portanto, estamos copiando a variável para outra variável, e o método impuro possivelmente está alterando a cópia, quando você pretende que ele altere a variável.
Esse é o perigo de passar uma estrutura somente leitura como um receptor . Também existe o perigo de passar uma estrutura que contém um campo somente leitura. Uma estrutura que contém um campo somente leitura é uma prática comum, mas é essencialmente um cheque de que o sistema de tipos não tem fundos para descontar; o "read-only-ness" de uma determinada variável é determinado pelo proprietário do armazenamento. Uma instância de um tipo de referência "possui" seu próprio armazenamento, mas uma instância de um tipo de valor não!
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);
Console.WriteLine(this.x);
}
}
Pode-se pensar que isso this.xnão vai mudar porque x é um campo somente leitura e Badnessnão é um construtor. Mas...
S s = new S(1);
s.Badness(ref s);
... demonstra claramente a falsidade disso. thise se sreferem à mesma variável, e essa variável não é somente leitura!