条件编译和框架目标

如果目标框架是较新的版本,那么我的项目的代码可能会大大改善。 我希望能够更好地利用C#中的条件编译来根据需要切换它们。

就像是:

#if NET40 using FooXX = Foo40; #elif NET35 using FooXX = Foo35; #else NET20 using FooXX = Foo20; #endif 

有没有这些符号是免费的? 我是否需要注入这些符号作为项目configuration的一部分? 似乎很容易做,因为我知道哪个框架是从MSBuild目标。

 /p:DefineConstants="NET40" 

更新:我的问题是人们如何处理这种情况? 你正在创build不同的configuration? 你是否通过命令行传递常量?

最好的方法之一是在你的项目中创build不同的构buildconfiguration:

 <PropertyGroup Condition=" '$(Framework)' == 'NET20' "> <DefineConstants>NET20</DefineConstants> <OutputPath>bin\$(Configuration)\$(Framework)</OutputPath> </PropertyGroup> <PropertyGroup Condition=" '$(Framework)' == 'NET35' "> <DefineConstants>NET35</DefineConstants> <OutputPath>bin\$(Configuration)\$(Framework)</OutputPath> </PropertyGroup> 

并在您的默认configuration之一:

 <Framework Condition=" '$(Framework)' == '' ">NET35</Framework> 

如果没有在其他地方定义,将会设置默认值。 在上面的情况下,每次构build每个版本时,OutputPath都会为您提供一个单独的程序集。

然后创build一个AfterBuild目标来编译你的不同版本:

 <Target Name="AfterBuild"> <MSBuild Condition=" '$(Framework)' != 'NET20'" Projects="$(MSBuildProjectFile)" Properties="Framework=NET20" RunEachTargetSeparately="true" /> </Target> 

这个例子将在第一次构build(编译并假定第一个构build是从上面的默认NET35)之后,重新编译整个项目的Frameworkvariables设置为NET20。 每个编译将具有正确设置的条件定义值。

以这种方式,你甚至可以排除项目文件中的某些文件,如果你不想要#ifdef文件:

 <Compile Include="SomeNet20SpecificClass.cs" Condition=" '$(Framework)' == 'NET20' " /> 

甚至引用

 <Reference Include="Some.Assembly" Condition="" '$(Framework)' == 'NET20' " > <HintPath>..\Lib\$(Framework)\Some.Assembly.dll</HintPath> </Reference> 

到目前为止,对我而言,另一种方法是将以下内容添加到项目文件中:

  <PropertyGroup> <DefineConstants Condition=" !$(DefineConstants.Contains(';NET')) ">$(DefineConstants);$(TargetFrameworkVersion.Replace("v", "NET").Replace(".", ""))</DefineConstants> <DefineConstants Condition=" $(DefineConstants.Contains(';NET')) ">$(DefineConstants.Remove($(DefineConstants.LastIndexOf(";NET"))));$(TargetFrameworkVersion.Replace("v", "NET").Replace(".", ""))</DefineConstants> </PropertyGroup> 

这需要像“v3.5”一样的TargetFrameworkVersion属性的值replace“v”和“。”。 获得“NET35”(使用新的属性function )。 然后删除任何现有的“NETxx”值并将其添加到DefinedConstants的末尾。 简化这个可能是可能的,但是我没有时间去捣鼓。

在VS中的项目属性的Build选项卡上查看,您将在条件编译符号部分中看到结果值。 在“应用程序”选项卡上更改目标框架版本,然后自动更改符号。 然后,您可以按照通常的方式使用#if NETxx预处理器指令。 在VS中更改项目似乎不会丢失自定义PropertyGroup。

请注意,这不会给你任何不同的Client Profile目标选项,但这对我来说不是问题。

我有这些解决scheme的问题,可能是因为我的初始常量是由这些属性预先构build的。

 <DefineConstants /> <DefineDebug>true</DefineDebug> <DefineTrace>true</DefineTrace> <DebugSymbols>true</DebugSymbols> 

Visual Studio 2010也因为分号冒出了一个错误,声称它们是非法字符。 错误消息给了我一个暗示,因为我可以看到预先build立的常量用逗号分隔,最终跟着我的“非法”分号。 经过一些重新格式化和按摩后,我能够想出一个适合我的解决scheme。

 <PropertyGroup> <!-- Adding a custom constant will auto-magically append a comma and space to the pre-built constants. --> <!-- Move the comma delimiter to the end of each constant and remove the trailing comma when we're done. --> <DefineConstants Condition=" !$(DefineConstants.Contains(', NET')) ">$(DefineConstants)$(TargetFrameworkVersion.Replace("v", "NET").Replace(".", "")), </DefineConstants> <DefineConstants Condition=" $(DefineConstants.Contains(', NET')) ">$(DefineConstants.Remove($(DefineConstants.LastIndexOf(", NET"))))$(TargetFrameworkVersion.Replace("v", "NET").Replace(".", "")), </DefineConstants> <DefineConstants Condition=" $(TargetFrameworkVersion.Replace('v', '')) >= 2.0 ">$(DefineConstants)NET_20_OR_GREATER, </DefineConstants> <DefineConstants Condition=" $(TargetFrameworkVersion.Replace('v', '')) >= 3.5 ">$(DefineConstants)NET_35_OR_GREATER</DefineConstants> <DefineConstants Condition=" $(DefineConstants.EndsWith(', ')) ">$(DefineConstants.Remove($(DefineConstants.LastIndexOf(", "))))</DefineConstants> </PropertyGroup> 

我将发布“高级编译器设置”对话框的屏幕快照(通过单击项目的“编译”选项卡上的“高级编译选项…”button打开)。 但作为一个新用户,我缺乏这样的代表。 如果你能看到截图,你会看到属性组自动填充的自定义常量,然后你会说:“我必须得到我的一些。”

编辑:得到这个代表令人惊讶的快..谢谢你们! 这是截图:

高级编译器设置

从清除常量开始:

 <PropertyGroup> <DefineConstants/> </PropertyGroup> 

接下来,build立你的debugging,跟踪和其他常量,如:

 <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <Optimize>false</Optimize> <DefineConstants>TRACE;DEBUG;$(DefineConstants)</DefineConstants> </PropertyGroup> 

最后,build立你的框架常量:

 <PropertyGroup Condition=" '$(TargetFrameworkVersion)' == 'v2.0' "> <DefineConstants>NET10;NET20;$(DefineConstants)</DefineConstants> </PropertyGroup> <PropertyGroup Condition=" '$(TargetFrameworkVersion)' == 'v3.0' "> <DefineConstants>NET10;NET20;NET30;$(DefineConstants)</DefineConstants> </PropertyGroup> <PropertyGroup Condition=" '$(TargetFrameworkVersion)' == 'v3.5' "> <DefineConstants>NET10;NET20;NET30;NET35;$(DefineConstants)</DefineConstants> </PropertyGroup> <PropertyGroup Condition=" '$(TargetFrameworkVersion)' == 'v4.0' "> <DefineConstants>NET10;NET20;NET30;NET35;NET40;$(DefineConstants)</DefineConstants> </PropertyGroup> <PropertyGroup Condition=" '$(TargetFrameworkVersion)' == 'v4.5' "> <DefineConstants>NET10;NET20;NET30;NET35;NET40;NET45;$(DefineConstants)</DefineConstants> </PropertyGroup> 

我认为这种方法是非常可读和可以理解的。

在.csproj文件中,在现有的<DefineConstants>DEBUG;TRACE</DefineConstants>行之后添加:

 <DefineConstants Condition=" '$(TargetFrameworkVersion.Replace(&quot;v&quot;,&quot;&quot;))' &gt;= '4.0' ">NET_40_OR_GREATER</DefineConstants> <DefineConstants Condition=" '$(TargetFrameworkVersion.Replace(&quot;v&quot;,&quot;&quot;))' == '4.0' ">NET_40_EXACTLY</DefineConstants> 

对Debug和Release构buildconfiguration执行此操作。 然后在你的代码中使用:

 #if NET_40_OR_GREATER // can use dynamic, default and named parameters #endif 

@Azarien,你的答案可以和Jeremy's结合在一起,而不是Debug | Release等。

对我来说,结合这两种变化效果最好,即包括使用#if NETXX的代码条件,并且一次性构build不同的框架版本。

我有这些在我的.csproj文件中:

  <PropertyGroup> <DefineConstants Condition=" '$(TargetFrameworkVersion.Replace(&quot;v&quot;,&quot;&quot;))' &gt;= '4.0' ">NET_40_OR_GREATER</DefineConstants> </PropertyGroup> <PropertyGroup Condition=" '$(TargetFrameworkVersion.Replace(&quot;v&quot;,&quot;&quot;))' == '3.5' "> <DefineConstants>NET35</DefineConstants> <OutputPath>bin\$(Configuration)\$(TargetFrameworkVersion)</OutputPath> </PropertyGroup> 

并在目标:

  <Target Name="AfterBuild"> <MSBuild Condition=" '$(TargetFrameworkVersion.Replace(&quot;v&quot;,&quot;&quot;))' &gt;= '4.0' " Projects="$(MSBuildProjectFile)" Properties="TargetFrameworkVersion=v3.5" RunEachTargetSeparately="true" /> </Target>