在编译时检测C#版本

是否可以使用预处理程序指令检测当前版本的C#是否为6或更高,因此在编译时?

我想做这样的事情:

var myVar = ...; string name; #if VERSION_6_OR_MORE name = nameof(myVar); #else name = "myVar"; #endif 

我使用Visual Studio 2015和C#6,所以我可以使用nameof() 。 但是,其他想要编译此代码的人可能正在使用旧版本,其中nameof()不存在。

我想使用预处理程序指令,因此我可以在C#6中保留nameof() ,但是不使用该版本的其他人也可以编译它。

nameof()运算符旨在减少维护:使用它时,您没有隐藏在字符串中的标识符,因此当您重命名变量,参数或成员时,您使用它的位置(例如ArgumentNullException(nameof(paramName)) )当你重构paramName名称时会更新。

现在使用你的方法,你有效地你的维护表面加倍而不是减少它(因为你现在有两个字符串变体 nameof()版本,两者都必须维护),完全否定nameof()的使用。

因此,如果您想支持较旧的C#版本,请坚持使用适用于这些版本的function:在字符串中使用标识符。

我不知道预先存在的指令。 但是,这是你可以做的:

  1. 定义两个构建配置:Say CSharp6和CSharp5(在配置管理器中)。
  2. 从配置管理器中选择C6,然后转到项目属性。 并定义一个符号说CSHARP6。
  3. 更改配置并转到CSharp5
  4. 再次打开项目属性并定义新符号:CSHARP5

然后你的指令条件如下:

 #if CSHARP6 name = nameof(myVar); #else name = "myVar"; #endif 

将配置文件的选择委派给构建代理程序,或作为编译项目的指导手册的一部分。

您可以在项目文件中显式指定语言版本并定义条件常量:

 6 DEBUG;TRACE DEBUG;TRACE;LANG_VERSION_6 

C#编译器不允许您使用数值定义符号 。 任何符号都是定义的未定义的 ,这意味着它只是一个布尔值。

#define // /define#if都不支持除布尔值之外的任何语法。

到目前为止,所有C#版本都与以前版本向后兼容(除了foreach循环中的迭代器变量语义等一些细微差别),因此如果您想编写与旧版本兼容的代码,请不要使用较新的function。

您可以在构建脚本中检测到可用的编译器版本后在外部定义符号,但是不值得麻烦的IMO,因为较低版本的C#代码比分散在代码周围的重复块更易读和可维护。

不确定这样的常数,但……

类似于typeof(int).Assembly.ImageRuntimeVersion可以在运行时提供帮助。

另外:您可以创建常量:

 USING_CS6 NOT_USING_CS6 

我没有测试过这个。