.NET Framework在更改特定属性之前是否执行内部检查?

时间:2013-05-30 17:10:48

标签: c# winforms optimization

在很多情况下,我碰巧处于一种情况,我想知道在设置变量之前是否必须执行IF检查(并增加方法的复杂性),或者这是由Windows或框架内部完成的。

作为示例,假设我们有一个不断触发的事件,例如Form的MouseMove事件。哪种方法更好用?是否在内部调用this.Cursor = Cursors.SizeNWSE;以确保在不需要时不执行任何操作或是否盲目执行代码?

示例A:

private void Form1_MouseMove(object sender, MouseEventArgs e)
{
    if (e.X - this.Width > -16 && e.Y - this.Height > -16)
    {
        this.Cursor = Cursors.SizeNWSE;
    }
    else
    {
        this.Cursor = Cursors.Arrow;
    }
}

例B:

private void Form1_MouseMove(object sender, MouseEventArgs e)
{
    if (e.X - this.Width > -16 && e.Y - this.Height > -16)
    {
        if (this.Cursor != Cursors.SizeNWSE)
            this.Cursor = Cursors.SizeNWSE;
    }
    else
    {
        if (this.Cursor != Cursors.Arrow)
            this.Cursor = Cursors.Arrow;
    }
}

3 个答案:

答案 0 :(得分:2)

简而言之:是的,支票效率最高。

深度:

我已经测试并进行了比较(代码在Form的Load事件上运行),并且惊讶地看到了实际的差异。

以下是我用来测试的代码:

this.Cursor = Cursors.SizeNWSE;

var sw1 = Stopwatch.StartNew();
for (var i = 0; i < 10000000; i++)
{
    this.Cursor = Cursors.SizeNWSE;
}
sw1.Stop();

var sw2 = Stopwatch.StartNew();
for (var i = 0; i < 10000000; i++)
{
    if (this.Cursor != Cursors.SizeNWSE)
    {
        this.Cursor = Cursors.SizeNWSE;
    }
}
sw2.Stop();

然后我换了两个,在第一个案例之前运行第二个案例,只是为了确定。结果是肯定的!

  

使用If:00:00:00.8065328

     

没有If:00:00:20.8631726

巨大的差异!没有检查的运行速度比使用支票运行慢20多倍。

这意味着在分配Cursor时,不会检查以确定是否可以忽略该分配。

但如果作业真的不能被忽视会怎样?如果每次都是不同的光标怎么办?

好问题!答案是进一步测试显示yes-check和no-check版本之间的差别非常小,当分配的游标与赋值时的实际游标完全相同时,所以赋值永远不会是多余的。差异显然是执行检查所需的额外时间。

ReSharper可能会警告您检查是多余的(“分配前的冗余检查”)但在这种情况下不是!当然不是。

如果你这么做很多,你想进行检查。

在MouseMove事件中,我建议进行检查,以防止滞后鼠标。即使您没有注意到它,也可能会在较慢的机器上显示。

答案 1 :(得分:2)

没有。为什么会这样? .NET完全没有理由这样做。在分配之前比较某些东西以防止“覆盖”相同的值只会增加复杂性并可能降低性能 - 我们在这里谈论的是微观微观优化。真正的性能微观影响在很大程度上取决于特定目标CPU架构的行为,缓存,时序,位置以及许多其他因素。

进行此类检查的唯一原因是,如果任何分配会触发一个操作(在您的示例Cursor中表示属性),如果完全相同的值将会是不需要的已经存放在特定的财产。

因此,如果您需要这样的行为,我建议将其封装到属性的setter中:

public Cursors Cursor
{
    get { return cursor; }
    set
    {
        // prevent reacting to “no change”
        if (cursor != value)
        {
            cursor = value;
            … perform some other action …
        }
    }
}
private Cursors cursor;

总而言之,不要担心性能,担心代码的语义和可读性。


更新:运行另一个答案中提供的测试代码时,我的结果在Core i5 3320M 2.60上大约介于00:00:00.0800000和00:00:00.1500000 之间GHz CPU。我的cursor被声明为局部变量。值得注意的是,有时无条件版本更快,有时条件更快。

如果在OPs的情况下,它被声明为一个属性(OP声明它是一个'变量'),它涉及一些复杂的内部过程,那么是的,具有条件赋值的版本可能会明显更快。但是,OP的问题没有表明这一点。

在现实世界的软件中,我怀疑会有如此多的光标变化,以至于它只能在一秒钟内考虑性能。

答案 2 :(得分:2)

.NET框架在设置之前不检查属性。以下是用于设置Cursor的{​​{1}}的反编译代码段:

Form

你可以看到每次都有一堆代码被执行。检查属性是否已更改,但它只会阻止框架运行几行。