C#可以提供static_assert吗?

grr*_*sel 11 c#

我正在寻找一种在C#编程语言中使用编译时断言的方法,例如用于C++的BOOST库或新的C++ 0x标准.

我的问题是双重的; 这可以通过标准的便携式C#实现; 或者,可以通过给定C#编译器的怪癖的非可移植假设来实现该行为吗?

谷歌的快速搜索揭示了以下一种技术的链接,其标准符合性和兼容性我不确定.

Pau*_*oke 6

在具有返回值的函数内,以下技巧/黑客工作(至少在Visual Studio 2005中,未在其他平台上检查过):

Something Foo()
{
    if (compiletime_const_condition)
    {
        // ...
        return something;
    }

    // no return statement at all
}
Run Code Online (Sandbox Code Playgroud)

它不漂亮,但它是我迄今为止最好的解决方案.

  • Func <object> static_assert =()=> {if(Position.TopLeft == 0)返回null; //没有回复}; (2认同)
  • 在 Visual Studio 2013 和 Visual Studio 2017 之间的某个时候,这个技巧停止工作,即使框架目标保持不变。现在所有的代码路径都必须返回一个值,即使它们永远不会被执行。 (2认同)

Dar*_*zka 6

该方法与其他没有内置静态断言的语言(Delphi、较旧的 C++ 等)相同:找到一种机制,将要断言的条件转换为编译器不满意的条件(如果条件为假) .

对于 C#,最容易利用的机制之一是关于将负文字/常量分配给无符号类型的警告。这已经在本讨论的某处(或至少在此处链接的页面之一)中被提及,但值得以其纯粹的形式展示。

这是一个保护两个常量的示例 -MODULUS_32MAX_N防止被编辑为违反预期的值:

const uint _0 = (ulong)MODULUS_32 * MODULUS_32 == MAX_N ? 0 : -666;
Run Code Online (Sandbox Code Playgroud)

-666使得错误消息可识别为静态断言。在这种情况下使用三元运算符比直接计算更可取,因为这样可以更容易地识别正在发生的事情(计算中的负结果比明确的、故意的分配更有可能归因于错误)。将常量命名为类似的名称_MAX_N_must_be_the_square_of_MODULUS_32会使事情更加明确。

这种类型的“静态断言”可靠地停止编译 - 如果有人篡改/warnaserror开关,这不仅仅是一些可能丢失的警告。

在某些范围内 - 例如,在函数内 - 可能有必要通过编译指示抑制“未使用值”警告:

#pragma warning disable 219
const uint _0 = (ulong)MODULUS_32 * MODULUS_32 == MAX_N ? 0 : -666;
#pragma warning restore 219
Run Code Online (Sandbox Code Playgroud)

C# 与 Delphi 非常相似,因为它缺少预处理器,这意味着静态断言及其机制不能打包成整洁的宏——如果你想使用它们,那么你必须立即输入所有管道。但就像在 Delphi 中一样,让编译器在编译时检查事物的好处是值得的。

  • 不错的黑客!通过这种方法,我能够断言某些匿名字段与其他类中的名称相同 `const ulong _0 = (ulong)((nameof(anonymousType.FieldName) == nameof(SomeClass.FieldName)) ? 0 : -666 );` (3认同)

Tob*_*ner -1

该代码是标准 C# 代码。它适用于任何编译器 - 但不一定在编译时。由于只有在条件中使用的参数恒定的情况下才可能进行编译时评估,我猜优化取决于编译器供应商/编译器开关。

在 C++ 中,静态断言要么是标准 (C++0x) 的一部分,要么是需要在编译时评估的模板,因此它们可以保证断言。

为了测试可移植性,我会使用不同的编译器,特别是没有任何优化,否则您可能会在程序启动时遇到异常。