我正在使用 Visual Studio 2010 + Resharper ,它会在以下代码中显示警告:
if (rect.Contains(point))
{
...
}
rect
是readonly Rectangle
字段,Resharper向我显示此警告:
“只为值类型的只读字段调用Impure方法。”
什么是不纯净的方法,为什么会向我显示此警告?
答案 0 :(得分:93)
首先,Jon,Michael和Jared的答案基本上是正确的,但我还有一些我想添加的内容。
“不纯”方法的含义是什么?
表征纯方法更容易。 “纯”方法具有以下特征:
例如,Math.Cos
是纯方法。它的输出仅取决于其输入,并且调用不会改变输入。
不纯的方法是一种不纯粹的方法。
将只读结构传递给不纯的方法有哪些危险?
有两个想到的。第一个是Jon,Michael和Jared指出的那个,这是Resharper警告你的那个。当你在一个struct上调用一个方法时,我们总是传递一个对接收者变量的引用,以防该方法希望改变变量。
那么如果你在一个值而不是一个变量上调用这样的方法呢?在这种情况下,我们创建一个临时变量,将值复制到其中,并传递对变量的引用。
readonly变量被认为是一个值,因为它不能在构造函数之外变异。所以我们将变量复制到另一个变量,当你打算改变变量时,不纯的方法可能会改变副本。
将readonly结构作为接收器传递是危险的。传递包含只读字段的结构也存在危险。包含只读字段的结构是一种常见的做法,但它实质上是在检查类型系统没有资金来支付现金;特定变量的“只读”由存储的所有者确定。引用类型的实例“拥有”其自己的存储,但值类型的实例不支持!
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
引用同一个变量,而 变量不是readonly!
答案 1 :(得分:48)
不纯的方法是不保证保留该值的方法。
在.NET 4中,您可以使用[Pure]
来装饰方法和类型,以声明它们是纯粹的,并且R#会注意到这一点。不幸的是,你不能将它应用于其他人的成员,并且你不能说服R#,据我所知,类型/成员在.NET 3.5项目中是纯粹的。 (这一直困扰着我Noda Time。)
想法是,如果你正在调用一个变量变量的方法,但你在一个只读字段上调用它,它可能不做你做的事情想要,所以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
}
}
如果每个实际上纯粹的方法都以这种方式声明,那么这将是一个非常有用的警告。不幸的是他们不是,所以有很多误报:(
答案 2 :(得分:14)
简短的回答是这是误报,你可以放心地忽略警告。
更长的答案是访问只读值类型会创建它的副本,因此方法所做的值的任何更改都只会影响副本。 ReSharper没有意识到Contains
是一种纯粹的方法(意味着它没有副作用)。 Eric Lippert在这里谈到它:Mutating Readonly Structs
答案 3 :(得分:11)
听起来Reshaprer认为方法Contains
可以改变rect
值。由于rect
是readonly struct
,因此C#编译器会对值进行防御性复制,以防止该方法改变readonly
字段。基本上最终的代码看起来像这样
Rectangle temp = rect;
if (temp.Contains(point)) {
...
}
Resharper在此警告你,Contains
可能会以一种临时丢失的方式改变rect
,因为它发生在临时状态。
答案 4 :(得分:5)
Impure方法是一种可能产生副作用的方法。在这种情况下,Resharper似乎认为它可以改变rect
。它可能没有,但证据链被打破了。