C#可以提供static_assert吗?

时间:2009-06-08 08:59:24

标签: c#

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

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

谷歌上的快速搜索显示以下链接指向一个technique,其标准符合性和兼容性我不确定。

7 个答案:

答案 0 :(得分:5)

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

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

    // no return statement at all
}

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

答案 1 :(得分:3)

Code Contracts将添加到C#4.0。它本质上是以优雅的方式完成的。

答案 2 :(得分:3)

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

对于C#,最容易利用的机制之一是关于将否定文字/常量赋值给无符号类型的警告。这已经在本讨论的某处(或者至少在这里链接的一个页面中)中提到过,但值得以纯粹的形式展示它。

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

const uint _0 = (ulong)MODULUS_32 * MODULUS_32 == MAX_N ? 0 : -666;

-666使错误消息可识别为由于静态断言。在这种情况下使用三元运算符更适合直接计算,因为这使得更容易识别正在进行的事情(计算中的否定结果更可能归因于错误而不是明确的,有意识的分配)​​。将常量命名为_MAX_N_must_be_the_square_of_MODULUS_32会使事情变得更加明确。

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

在某些范围内 - 例如,在功能范围内 - 可能需要抑制未使用的值'通过pragma警告:

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

C#与Delphi非常相似,它缺少预处理器,这意味着静态断言及其机制无法打包成整齐的宏 - 如果你想使用它们,那么你必须在那里输入所有的管道。但就像在Delphi中一样,让编译器在编译时检查事物的好处不仅值得付出小小的努力。

答案 3 :(得分:1)

您提供的链接中的代码将按照与此类似的结构进行编译:

byte a;
if (RenderQuality.Low < RenderQuality.Medium)
    a = 0;
else a = -1;

因此编译器会抛出错误。三元(条件)运算符?:只不过是像'??'这样的语法糖运营商。
c#中没有静态断言,因为其中没有模板(泛型看起来与模板类似但存在很多差异,并且它们没有模板那么强大)。使用条件语句和预处理器定义可以实现某些功能。有关详细信息,请参阅this topic

答案 4 :(得分:1)

您可能会尝试使用类似

的内容
( 0 / ( condition ? 1 : 0 ) )

理想情况下,编译器需要为编译原因评估值(例如控制编译的某些属性,可能是结构布局)。

编辑:因为属性参数必须是常量表达式,我假设它们总是在编译期间进行评估,因此任何属性都可能就足够了。

EDIT2: 另一种方法是创建自定义属性(例如StaticCheck),采用布尔值,也许是字符串和工具,它将作为构建后事件运行,并使用反射来检查所有这些属性。不像直接支持它那么好,但比分区黑客更干净。

答案 5 :(得分:0)

实际上,当我在编译时将表达式更改为无法评估(并因此折叠)的内容时,我得到了一个不同的异常:

  

无法隐式转换类型'int'   '字节'。显式转换   存在(你是否错过演员表?)

不进行折叠的编译器应该生成类似的编译错误。因此,在这样的编译器上,在你取出所有断言之前它不会编译。不漂亮,但最好在运行时获得惊喜。

答案 6 :(得分:-1)

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

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

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