Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 条件编译和框架目标_C#_.net 3.5_Msbuild_.net 4.0 - Fatal编程技术网

C# 条件编译和框架目标

C# 条件编译和框架目标,c#,.net-3.5,msbuild,.net-4.0,C#,.net 3.5,Msbuild,.net 4.0,如果目标框架是较新的版本,我的项目的代码可能会有一些小的改进。我希望能够更好地利用C#中的条件编译,根据需要切换这些条件 比如: #if NET40 using FooXX = Foo40; #elif NET35 using FooXX = Foo35; #else NET20 using FooXX = Foo20; #endif 这些符号有免费的吗?我是否需要将这些符号作为项目配置的一部分插入?这似乎很容易做到,因为我知道MSBuild针对的是哪个框架 /p:DefineConstant

如果目标框架是较新的版本,我的项目的代码可能会有一些小的改进。我希望能够更好地利用C#中的条件编译,根据需要切换这些条件

比如:

#if NET40
using FooXX = Foo40;
#elif NET35
using FooXX = Foo35;
#else NET20
using FooXX = Foo20;
#endif
这些符号有免费的吗?我是否需要将这些符号作为项目配置的一部分插入?这似乎很容易做到,因为我知道MSBuild针对的是哪个框架

/p:DefineConstants="NET40"

人们是如何处理这种情况的?您正在创建不同的配置吗?是否通过命令行传入常量?

实现这一点的最佳方法之一是在项目中创建不同的生成配置:

<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>

NET20
bin\$(配置)\$(框架)
网络35
bin\$(配置)\$(框架)
在其中一种默认配置中:

<Framework Condition=" '$(Framework)' == '' ">NET35</Framework>
NET35
如果没有在其他任何地方定义它,它将设置默认值。在上述情况下,每次构建每个版本时,OutputPath将为您提供一个单独的程序集

然后创建一个后构建目标来编译不同的版本:

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

本例将在第一次构建之后重新编译整个项目,并将框架变量设置为NET20(编译这两个变量,并假设第一次构建是上面的默认NET35)。每个编译都将正确设置条件定义值

通过这种方式,如果您希望w/o必须#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>

美元(定义常量)$(TargetFrameworkVersion.Replace(“v”,“NET”).Replace(“.”,”))
$(DefineConstants.Remove($(DefineConstants.LastIndexOf(“;NET”))$(TargetFrameworkVersion.Replace(“v”,“NET”).Replace(“.”,”))
这将采用TargetFrameworkVersion属性的值,类似于“v3.5”,替换“v”和“.”以获得“NET35”(使用新功能)。然后,它删除任何现有的“NETxx”值,并将其添加到DefinedConstants的末尾。也许可以简化这个过程,但我没有时间去做

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


注意,对于客户端概要文件目标选项,这似乎没有给您带来任何不同,但这对我来说不是问题。

在.csproj文件中,在现有的
调试之后;跟踪
行,添加以下内容:

<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>

@Azarien,你的答案可以和Jeremy的结合在一起,把它放在一个地方,而不是调试、发布等等

对我来说,将这两种变体结合起来效果最好,即使用#if NETXX在代码中包含条件,并一次性构建不同的框架版本

我的.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>

净40或以上
网络35
bin\$(配置)\$(TargetFrameworkVersion)
在目标方面:

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

我对这些解决方案有问题,可能是因为我的初始常量是由这些属性预先构建的

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

真的
真的
真的
VisualStudio2010也因为分号而抛出了一个错误,声称它们是非法字符。错误消息给了我一个提示,因为我可以看到用逗号分隔的预构建常量,最后是我的“非法”分号。经过一些重新格式化和按摩,我能够想出一个适合我的解决方案

<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>

$(DefineConstants)$(TargetFrameworkVersion.Replace(“v”,“NET”).Replace(“.”,”),
$(DefineConstants.Remove($(DefineConstants.LastIndexOf(“,NET”))$(TargetFrameworkVersion.Replace(“v”,“NET”).Replace(“,”),
$(定义常数)净20或更大,
$(定义常数)净值大于等于35
$(DefineConstants.Remove($(DefineConstants.LastIndexOf(“,”)))
我将发布高级编译器设置对话框的屏幕截图(通过单击项目编译选项卡上的“高级编译选项…”按钮打开)。但作为一个新用户,我缺少这样做的代表。如果你能看到屏幕截图,你会看到属性组自动填充的自定义常量,然后你会说,“我要给我一些。”


编辑:获得该代表的速度惊人。。谢谢大家!以下是截图:


首先清除常数:

<PropertyGroup>
  <DefineConstants/>
</PropertyGroup>
<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>

接下来,构建调试、跟踪和其他常量,如:

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

真的
满的
假的
痕迹;调试$(定义常量)
最后,构建框架常量:

<PropertyGroup>
  <DefineConstants/>
</PropertyGroup>
<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>

NET10;NET20$(定义常量)
NET10;NET20;NET30$(定义常量)
NET10;NET20;NET30;NET35$(定义常量)
NET10;NET20;NET30;NET35;NET40$(定义常量)
NET10;NET20;NET30;NET35;NET40;NET45$(定义常量)

我认为这种方法可读性强,易于理解。

如果您使用的是.NET核心构建系统,您可以使用其预定义的符号(实际上已经与您的示例匹配,并且不需要对
.csproj
!)进行任何更改:

#如果是NET40
使用FooXX=Foo40;
#elif NET35
使用FooXX=Foo35;
#else NET20
使用FooXX=Foo20;
#恩迪夫
预定义符号列表记录在和中:

.NET Framework:
NETFRAMEWORK
NET20
NET35
NET40
NET45
NET451
NET452
NET461
NET462
NET47
NET471
NET472