我正在使用Visual Studio 2010 + Resharper并在以下代码中显示警告:
if (rect.Contains(point))
{
...
}
Run Code Online (Sandbox Code Playgroud)
rect是一个readonly Rectangle领域,Resharper向我展示了这个警告:
"为值只读的字段调用Impure方法."
什么是不纯的方法,为什么这个警告会显示给我?
Eri*_*ert 95
首先,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);
}
}
Run Code Online (Sandbox Code Playgroud)
有人认为这this.x不会改变,因为x是一个只读字段而Badness不是构造函数.但...
S s = new S(1);
s.Badness(ref s);
Run Code Online (Sandbox Code Playgroud)
......清楚地表明了这种虚假.this并s引用相同的变量,该变量不是只读的!
Jon*_*eet 51
不纯的方法是不保证保留原样的方法.
在.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
}
}
Run Code Online (Sandbox Code Playgroud)
如果每个实际上纯粹的方法都以这种方式声明,那么这将是一个非常有用的警告.不幸的是他们不是,所以有很多误报:(
Mic*_*Liu 15
简短的回答是这是误报,你可以放心地忽略警告.
更长的答案是访问只读值类型会创建它的副本,因此方法所做的值的任何更改都只会影响副本.ReSharper没有意识到这Contains是一种纯粹的方法(意味着它没有副作用).Eric Lippert在这里谈到它:变异Readonly Structs
Jar*_*Par 11
听起来Reshaprer认为该方法Contains可以改变rect价值.因为rect是readonly structC#编译器制作值的防御副本以防止该方法变异readonly字段.基本上最终的代码看起来像这样
Rectangle temp = rect;
if (temp.Contains(point)) {
...
}
Run Code Online (Sandbox Code Playgroud)
Resharper在这里警告你Contains可能会rect以一种会立即丢失的方式发生变异,因为它发生在一个临时的.
| 归档时间: |
|
| 查看次数: |
16184 次 |
| 最近记录: |