【问题标题】:C# cascading assignment [closed]C#级联赋值[关闭]
【发布时间】:2012-10-02 00:39:26
【问题描述】:

当我们分配这样的值时是否会降低性能?

Dropdown1.Enable = dropdown2.Enable = dropdown3.Enable = false;

提前致谢。

【问题讨论】:

  • 不知道为什么这个问题被标记为过于本地化。这是相当实用的,而不是“本地化”的 IMO。

标签: c# performance-testing assignment-operator


【解决方案1】:

答案是没有影响——相当于三个赋值语句。

甚至没有调用任何get 操作,如下所示:

控制台应用项目:

using System;
using System.Diagnostics;

namespace ConsoleApplication5
{
    public class X

    {
        private int _a;
        private int _b;

        public int A
        {
            get
            {
                Console.WriteLine("get A");
                return _a + 1;
            }
            set
            {
                Console.WriteLine("set A");
                _a = value;
            }
        }

        public int B
        {
            get
            {
                Console.WriteLine("get B");
                return _b + 2;
            }
            set
            {
                Console.WriteLine("set B");
                _b = value;
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var x = new X();

            Console.WriteLine("Assign");
            int y = x.B = x.A = 125;

            Console.WriteLine("Read");
            Console.WriteLine("y " + y + " x.B " + x.B + " x.A " + x.A);

            Console.ReadLine();
        }
    }
}

生成:

Assign
set A
set B
Read
get B
get A
y 125 x.B 127 x.A 126

请注意,在分配阶段,不会调用任何“get”,即使 A 和 B 的 getter 返回的值与设置在它们上的值不同,最终分配给 y 的值是源值表达式的 RHS。

【讨论】:

  • 刚刚检查并没有看到这种行为记录在 c# 规范中。我想知道是吗?
【解决方案2】:

我可能对其他两个答案有误解,但我认为没有任何getters 被解雇。在所有三种情况下,为属性触发的是 setter。此外,我很确定 IL 只是将 false 值推入堆栈三次,并为每次触发一次设置器。

对于以下课程:

public class Test
{
    public bool Prop { get; set; }
}

对于t1.Prop = t2.Prop = t3.Prop = false;,IL 是:

IL_0013:  ldloc.0     //t1
IL_0014:  ldloc.1     //t2
IL_0015:  ldloc.2     //t2
IL_0016:  ldc.i4.0    //false
IL_0017:  dup         //dup the false on the stack
IL_0018:  stloc.3     
IL_0019:  callvirt    UserQuery+Test.set_Prop //set value
IL_001E:  nop         
IL_001F:  ldloc.3     
IL_0020:  dup         //dup the false on the stack
IL_0021:  stloc.3     
IL_0022:  callvirt    UserQuery+Test.set_Prop //set value
IL_0027:  nop         
IL_0028:  ldloc.3     
IL_0029:  callvirt    UserQuery+Test.set_Prop //set value

为:

t1.Prop = false;
t2.Prop = false;
t3.Prop = false;

IL 是:

IL_0012:  stloc.2     
IL_0013:  ldloc.0     
IL_0014:  ldc.i4.0    //false  
IL_0015:  callvirt    UserQuery+Test.set_Prop //set value
IL_001A:  nop         
IL_001B:  ldloc.1     
IL_001C:  ldc.i4.0    //false
IL_001D:  callvirt    UserQuery+Test.set_Prop //set value
IL_0022:  nop         
IL_0023:  ldloc.2     
IL_0024:  ldc.i4.0    //false 
IL_0025:  callvirt    UserQuery+Test.set_Prop //set value

所以 IL 非常接近,真正唯一的区别是点击 ldc.i4.0 三次,或者点击一次并在堆栈上复制两次。性能无关紧要。但是,如果获得 false 值是一项不平凡的操作,则将其放在三行上需要更长的时间,但您可以轻松编写:

bool value = SomeLongOperation();
t1.Prop = value;
t2.Prop = value;
t3.Prop = value;

因此,请尽一切可能提高公司的可读性和/或您的标准。

编辑:实际上,如果编译器/JIT 将单独的行条目优化为基本上第一种情况(或更快的情况)或其他优化状态,我不会感到惊讶。真的,唯一需要关心的是最后一个代码示例;如果你需要做SomeLongOperation() 来获取价值,只做一次。之后,做任何可读的事情。

【讨论】:

    【解决方案3】:

    你通常会这样做:

    variable1 = varaible2 = variable3 = 123
    

    但是由于Enable 属性是一个getter,所以这是不可能的。 在内部,getter 看起来像这样:

    public bool Enabled
    {
        get
        {
            return something;
        }
        set
        {
            something = value;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-08
      • 1970-01-01
      • 2017-02-22
      • 2017-07-05
      • 2013-01-20
      • 2014-10-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多