【问题标题】:Which is more efficient way to assign values to variables in .NET?在 .NET 中为变量赋值更有效的方法是什么?
【发布时间】:2008-10-28 01:46:36
【问题描述】:

这是我一直想知道的,但从来没有打扰过。

为临时变量分配一个值比继续使用该值更有效吗?一个例子可能更清楚:

string s = reader.GetItem[0].ToString();
someClass.SomeField  = s;
someOtherClass.someField = s;

someClass.SomeField  = reader.GetItem[0].ToString();
someOtherClass.someField = reader.GetItem[0].ToString();

我最初的想法是顶级示例会更有效,因为它不必访问 Item 集合或调用 ToString。

很想听听其他人的想法,或以任何方式给出明确的答案。

【问题讨论】:

    标签: .net performance


    【解决方案1】:

    编译器无法知道右侧的表达式是否有副作用,因此如果您对其进行两次编码,它必须重新计算它。因此,第一个更有效,因为它不会重新执行 GetItem 和 ToString 调用。

    因此,如果您的程序员知道这些调用是纯/幂等的,那么您应该以第一种方式编写代码。

    【讨论】:

      【解决方案2】:

      正如Brian 所说,第一种方式会更高效,尽管它在现实世界中是否有很大的不同取决于重复函数的成本,以及这段代码作为一个整体被调用的频率。

      但是,除了更高效之外,第一种方式更能表明意图 - 您的意思是为两件事分配相同的值。它还有助于可维护性,因为如果需要更改,您只需在一个地方进行更改。对我来说,这两者通常都比效率更重要。

      【讨论】:

      • 有些人可能会说他们讨厌这个,但我会经常做以下事情来明确多个变量被初始化为相同的值。 oneVar = anotherVar = someFunctionCall();
      • 在哪些 .net 语言中合法?
      • 至少在 C# 中有效。我对@grantwparks 的建议意见不一——一方面,它非常直接地表达了将两者初始化为相同值的意图。另一方面,我一直不喜欢这种做法难以阅读。值得深思...
      【解决方案3】:

      还有另一种选择——复合赋值:

      someOtherClass.someField  = someClass.SomeField  = reader.GetItem[0].ToString();
      

      通过这种用法,编译器将评估reader.GetItem[0].ToString()一次,并使用它来分配给两个成员(它确实使用getof someClass )。它通过复制堆栈上的值来做到这一点(不需要显式本地)。

      非常高效,但老实说,我不会对带有变量的原始版本感到太兴奋。

      【讨论】:

        【解决方案4】:

        假设ToString 函数不只是提供对某个预制内部对象的引用,那么必须非常清楚的是,第一个版本(仅对其进行一次调用)将是最快的。但是,如果这是一个性能问题,您是否应该关心则完全不同。

        确实考虑的一个问题是,如果从另一个线程同时访问/更改项目,则第二个示例可能会在第一行和第二行呈现不同的结果。

        【讨论】:

          【解决方案5】:

          如果我要多次使用它,我只是习惯于在局部变量中存储一个值。不过,通常是因为我更喜欢代码的紧凑性,而不是太在意效率——不过,如果在循环中重复使用它,我肯定会这样做。

          有时,我不一致,只会重新输入,特别是如果只使用访问器而不调用需要计算的方法。

          【讨论】:

            【解决方案6】:

            这是我的经验法则。如有疑问,profile your code。优化编译器可以删除大量代码,从而使您的代码运行得更快。

            还必须考虑两个事实:

            • .NET 分配内存非常快。
            • 由于额外的页面错误、引用的局部性差、垃圾收集过多,过多的垃圾会降低您的应用程序的速度。

            这意味着粗略观察下,您的代码可能非常快,但如果您生成大量垃圾,您的程序运行一段时间后性能会受到影响。

            【讨论】:

            • 一个变量不添加垃圾; “s”场景没有额外的堆分配。然而,重新使用索引器可能会,因为 .ToString() 可能会导致不同的字符串对象(除非该项目已经是一个字符串)。
            【解决方案7】:

            可读性很重要。 “s”命名变量有什么用?

            另外,使用字段名代替 [0] 会更有意义。

            【讨论】:

            • 使用名称也会使其变慢;一个平衡的行为。
            【解决方案8】:

            还有其他问题需要考虑。如果使用s 分配给其他变量,与s 被多行代码初始化的位置是分开的,那么您就有可能其他人会出现并稍后添加代码来改变值s 在它的使用之间,或者以某种方式围绕原始分配分支到 s

            我经常看到的一件事是将函数赋值给一个变量,即使该值仅在一个地方使用,我讨厌这样,因为(并且该变量的名称无关紧要) 这不可避免地导致必须去寻找该变量被分配到哪里才能知道它真正代表什么。将函数的返回值直接分配给将要使用它的对象,明确指示正在发生的事情。

            在编程中有一个派别相信“无变量编程”(几十年前著名的“无跳转编程”论文的味道)。例如,XSL,虽然它确实有“变量”,但它们在单个范围内的初始分配之后是不可变的。有人说,这有助于保证没有意外的副作用。

            【讨论】:

              猜你喜欢
              • 2015-07-09
              • 2019-03-05
              • 2019-08-26
              • 2017-09-21
              • 1970-01-01
              • 1970-01-01
              • 2020-12-18
              • 1970-01-01
              • 2014-11-10
              相关资源
              最近更新 更多