在C#

时间:2019-04-15 19:35:03

标签: c# c++ performance

有什么方法可以在C#中模拟C ++值模板参数?

template<bool flag>
void Method()
{
     // Do some work
     if constexpr(flag)
     {
          // Do something specific
     }
     // Do some more work
}

这样它将生成方法的两个版本,可以这样调用:

Method<false>();
Method<true>();

这是出于性能方面的考虑,因此最好不要在Method内进行其他调用。 Method是性能至关重要的部分,被称为数十亿次,因此从中压缩每个CPU周期非常重要。

另一方面,它的逻辑比较复杂,所以我宁愿没有两个副本。

我认为我可以对泛型做一些事情,但这并不是性能的最佳选择。因此,现在我唯一能想到的方法就是为其创建某种模板代码生成器。但是也许还有其他选择? 也许可以使用Roslyn编译该方法的两个版本,以便使用特定参数创建该方法的两个优化版本?

void Method(bool flag)
{
     // Do some work
     if (flag)
     {
          // Do something specific
     }
     // Do some more work
}

以便我可以将其编译为:

void Method_false(false)
{
     // Do some work
     // Do some more work
}

和:

void Method_true(true)
{
     // Do some work
     // Do something specific
     // Do some more work
}

有可能吗?

2 个答案:

答案 0 :(得分:2)

在C#中无法进行元编程。在以下SO问题中以代码转换工具的形式寻找可能的替代方法:Is metaprogramming possible in C#?

答案 1 :(得分:1)

您不能直接从语言中执行此操作,但这是可能的,因为JIT足够聪明。创建一个接口和两个结构:

public interface IBool
{
    bool IsTrue();
}

public struct True : IBool
{
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public bool IsTrue()
    {
        return true;
    }
}

public struct False : IBool
{
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public bool IsTrue()
    {
        return false;
    }
}

请注意,IsTrue的实现标记有MethodImpl属性。现在,将您的Method改写为通用的

public static void Method<T>(ref T flag) where T : struct, IBool
{
    if (flag.IsTrue())
    {
        Console.WriteLine(42);
    }
    else
    {
        Console.WriteLine(24);
    }
}

有一件很重要的事情:Tstruct约束,因此JIT意识到没有T的继承类型,没有人可以覆盖IsTrue的返回值。此外,由于将内联此方法,因此JIT用常量替换对IsTrue的调用。而当您拥有

if (false)
{
    // some code
}

这意味着将删除整个代码块。结果,JIT将创建Method的两个实现:首先是if部分的内容,而seconf是else部分的内容。您可以在反汇编窗口中进行检查:

Two calls with different target address