【问题标题】:Can I avoid this copy&paste of code?我可以避免这种代码的复制和粘贴吗?
【发布时间】:2013-03-31 16:51:39
【问题描述】:

我有两个函数,它们的内容很相似。

// mock-up code

bool A() {
    while(1000000) {
        // 3 lines of A() specific code
        // 15 lines of shared code, pasted in
        // 1 lines of A() specific code
    }
}
bool B() {
    while(1000000) {
        // 2 lines of B() specific code
        // 15 lines of shared code, pasted in
        // 2 lines of B() specific code
    }
}     

我不希望将 15 行共享代码粘贴到两个函数中(因为这些行非常复杂,如果我稍后更改该代码,我不想记住更改它两个地方)。

如果我将这 15 行代码放入一个单独的函数中,我会严重影响性能(JIT 拒绝内联它;可能是由于参数列表中的结构和/或“复杂”的流控制元素)。

还有其他方法,还是我运气不好?

【问题讨论】:

  • Hans Passant 的问题可能吗?你的独立函数的返回类型是什么?
  • 拆分成小方法,增加可重用性
  • @JeremyChild 或 Jon Skeet
  • 也许尝试另一个 C# 实现,即mono-project.com 或等到您的 C# 实现(即编译器和运行时)得到改进。或者使用一些文本预处理器。
  • @Barmar C# 只有“已定义或未定义”的宏,它们不会扩展到任何东西

标签: c# optimization


【解决方案1】:

您所说的这种“显着”的性能影响远没有您想象的那么重要。

如果它很重要,您可以尝试告诉 JIT 编译器使用 MethodImplOptions Enumeration 内联它,尽管如果方法不是虚拟的,他应该这样做。 For more information.

示例(来自 MSDN):

using System;
using System.Globalization;
using System.Runtime.CompilerServices;

public class Utility
{
   [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] 
   public static string GetCalendarName(Calendar cal)
   {
      return cal.ToString().Replace("System.Globalization.", "").
                 Replace("Calendar", "");
   }
}

【讨论】:

  • 最后一个答案好像被删了,我这里再发一次。 A() 是Eric Lippert's A* 探路者,B() 是一个稍微修改过的版本,类似于 Dijkstra 的算法。目前,性能与这些算法的 C++ 实现相比具有竞争力(这是设计目标)。但是,加上非内联函数调用,性能没有竞争力。
  • 您不能强制方法在 C# 中内联(就像在 C++ 中一样),AggressiveInlining 可能 内联它,可能不会,或更糟(可能因不同硬件而异)。可悲的是,它甚至不是我的选择,代码的要求是 .NET Framework 2.0 兼容性。
【解决方案2】:

我们不要寻找太复杂的东西,那又如何呢?不是那么干净,但这可能是你必须付出的代价才能同时拥有非复制和性能:

boolean AorB (boolean flagA) {
    while(1000000) {
        if (flagA) {
            // 3 lines of A() specific code
        }
        else {
            // 1 line of B() specific code
        }

        // 15 lines of shared code, pasted in

        if (flagA) {
            // 2 lines of A() specific code
        }
        else {
            // 2 lines of B() specific code
        }
    }
}

【讨论】:

  • 我使用goto 声明对该设计进行了尝试。我的理由是,使用goto,可能无需在while 循环的每次迭代 上评估AorB 是否作为A()B() 发挥作用。我没有成功。
  • 为什么是goto?它会让你的代码更难读。从我发布的内容开始,看看它是如何进行的。如果你喜欢它,你可以想你想写它的方式。并且不要试图优化到通过while 迭代节省if 的地步,这没有任何意义:.NET VM 可能会自行解决问题,也许您认为不是发生的事情。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-02
  • 2020-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-19
相关资源
最近更新 更多