私はVisual Studio 2010+Resharperを使用していますが、警告が表示されます次のコード:
if (rect.Contains(point))
{
...
}
rect
はreadonly Rectangle
フィールド、およびResharperはこの警告を表示します。
「Impureメソッドは、値型の読み取り専用フィールドに対して呼び出されます。」
不純な方法とは何か、なぜこの警告が表示されるのか?
まず、Jon、Michael、Jaredの答えは基本的に正しいですが、私はそれらに追加したいことがいくつかあります。
「不純な」方法とはどういう意味ですか?
純粋なメソッドを特徴付けることは簡単です。 「純粋な」メソッドには、次の特性があります。
例えば、 Math.Cos
は純粋なメソッドです。出力は入力のみに依存し、入力は呼び出しによって変更されません。
不純な方法とは、純粋ではない方法です。
読み取り専用の構造体を渡してメソッドを不純にする危険性は何ですか?
思い浮かぶのは2つあります。 1つ目はJon、Michael、Jaredが指摘したもので、これはResharperがあなたに警告しているものです。構造体でメソッドを呼び出すとき、メソッドが変数を変更したい場合に備えて、常にレシーバーである変数への参照を渡します。
それでは、変数ではなく値でそのようなメソッドを呼び出すとどうなりますか?その場合、一時変数を作成し、その変数に値をコピーして、変数への参照を渡します。
読み取り専用変数は、コンストラクターの外部で変更できないため、値と見なされます。そのため、変数を別の変数にコピーしていますが、不純なメソッドは、変数を変更しようとするときに、コピーを変更している可能性があります。
これは、読み取り専用の構造体をreceiverとして渡す危険です。また、読み取り専用フィールドを含む構造体を渡す危険もあります。読み取り専用フィールドを含む構造体は一般的な方法ですが、本質的には、型システムに現金化する資金がないことをチェックします。特定の変数の「読み取り専用」は、ストレージの所有者によって決定されます。参照型のインスタンスは自身のストレージを「所有」しますが、値型のインスタンスは所有しません!
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);
}
}
this.x
は変更されません。xは読み取り専用フィールドであり、Badness
はコンストラクタではないためです。だが...
S s = new S(1);
s.Badness(ref s);
...その間違いを明確に示しています。 this
とs
は同じ変数を参照し、that変数は読み取り専用ではありません!
不純なメソッドとは、値をそのままにしておくことが保証されていないメソッドです。
.NET 4では、メソッドと型を [Pure]
純粋であることを宣言します。R#はこれに注意します。残念ながら、それを他の誰かのメンバーに適用することはできません。また、私の知る限り、型/メンバーが.NET 3.5プロジェクトで純粋であることをR#に納得させることはできません。 (これは Noda Time 常に私に噛みつきます。)
ideaは、変数を変更するメソッドを呼び出すが、読み取り専用フィールドで呼び出す場合は、おそらくnotあなたがしたいことをしているので、R#はこれについて警告します。例えば:
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
}
}
実際に純粋なすべてのメソッドがそのように宣言された場合、これは非常に便利な警告になります。残念ながらそうではないので、多くの誤検知があります:(
簡単な答えは、これは誤検知であり、警告を安全に無視できることです。
より長い答えは、読み取り専用の値型にアクセスすると、そのcopyが作成されるため、メソッドによって行われた値への変更は、コピー。 ReSharperはContains
が純粋なメソッドであることを認識しません(つまり、副作用がないことを意味します)。 Eric Lippertがここでそれについて語っています: Mutating Readonly Structs
Reshaprerは、メソッドContains
がrect
の値を変更できると信じているようです。 rect
はreadonly struct
C#コンパイラは、メソッドがreadonly
フィールドを変更しないように値の防御コピーを作成します。基本的に最終コードは次のようになります
Rectangle temp = rect;
if (temp.Contains(point)) {
...
}
Resharperは、Contains
がrect
を変更する可能性があることを警告しています。
不純メソッドとは、副作用が生じる可能性のあるメソッドです。この場合、Resharperはrect
を変更できると考えているようです。おそらくそうではありませんが、一連の証拠が壊れています。