我有一些使用扩展方法的代码,但是使用VS2008中的编译器在.NET 2.0下编译。为此,我必须声明ExtensionAttribute:
/// <summary>
/// ExtensionAttribute is required to define extension methods under .NET 2.0
/// </summary>
public sealed class ExtensionAttribute : Attribute
{
}
但是,我现在想要包含该类的库也可以在.NET 3.0,3.5和4.0下编译 - 没有'ExtensionAttribute在多个地方定义'警告。
当目标框架版本是.NET 2时,是否有任何编译时指令可用于仅包含ExtensionAttribute?
答案 0 :(得分:59)
带有'创建N个不同配置'的链接SO问题当然是一个选项,但是当我需要这个时,我只是添加了条件的DefineConstants元素,所以在我的Debug | x86(例如)之后,现有的DefineConstants for DEBUG ; TRACE,我添加了这两个,检查了在csproj文件的第一个PropertyGroup中设置的TFV中的值。
<DefineConstants Condition=" '$(TargetFrameworkVersion)' == 'v4.0' ">RUNNING_ON_4</DefineConstants>
<DefineConstants Condition=" '$(TargetFrameworkVersion)' != 'v4.0' ">NOT_RUNNING_ON_4</DefineConstants>
显然,你不需要两者,但它只是提供eq和ne行为的例子 - #else和#elif也可以正常工作:)
class Program
{
static void Main(string[] args)
{
#if RUNNING_ON_4
Console.WriteLine("RUNNING_ON_4 was set");
#endif
#if NOT_RUNNING_ON_4
Console.WriteLine("NOT_RUNNING_ON_4 was set");
#endif
}
}
然后我可以在目标3.5和4.0之间切换,它会做正确的事情。
答案 1 :(得分:33)
到目前为止,我有一些改进答案的建议:
使用Version.CompareTo()。测试相等性不适用于以后的框架版本,但尚未命名。 E.g。
<CustomConstants Condition=" '$(TargetFrameworkVersion)' == 'v4.0' ">
与v4.5或v4.5.1不匹配,这通常是您想要的。
使用导入文件,以便只需定义一次这些附加属性。我建议将导入文件保留在源代码管理下,以便更改与项目文件一起传播,而无需额外的努力。
在项目文件的末尾添加import元素,使其独立于任何特定于配置的属性组。这还有一个好处,就是在项目文件中需要一个额外的行。
<!--
******************************************************************
Defines the Compile time symbols Microsoft forgot
Modelled from https://msdn.microsoft.com/en-us/library/ms171464.aspx
*********************************************************************
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<DefineConstants Condition="$([System.Version]::Parse('$(TargetFrameworkVersion.Substring(1))').CompareTo($([System.Version]::Parse('4.5.1')))) >= 0">$(DefineConstants);NETFX_451</DefineConstants>
<DefineConstants Condition="$([System.Version]::Parse('$(TargetFrameworkVersion.Substring(1))').CompareTo($([System.Version]::Parse('4.5')))) >= 0">$(DefineConstants);NETFX_45</DefineConstants>
<DefineConstants Condition="$([System.Version]::Parse('$(TargetFrameworkVersion.Substring(1))').CompareTo($([System.Version]::Parse('4.0')))) >= 0">$(DefineConstants);NETFX_40</DefineConstants>
<DefineConstants Condition="$([System.Version]::Parse('$(TargetFrameworkVersion.Substring(1))').CompareTo($([System.Version]::Parse('3.5')))) >= 0">$(DefineConstants);NETFX_35</DefineConstants>
<DefineConstants Condition="$([System.Version]::Parse('$(TargetFrameworkVersion.Substring(1))').CompareTo($([System.Version]::Parse('3.0')))) >= 0">$(DefineConstants);NETFX_30</DefineConstants>
</PropertyGroup>
</Project>
通过在标记之前添加结尾,从.csproj文件中引用它。
…
<Import Project="VersionSpecificSymbols.Common.prop" />
</Project>
您需要修复路径以指向放置此文件的公共/共享文件夹。
namespace VersionSpecificCodeHowTo
{
using System;
internal class Program
{
private static void Main(string[] args)
{
#if NETFX_451
Console.WriteLine("NET_451 was set");
#endif
#if NETFX_45
Console.WriteLine("NET_45 was set");
#endif
#if NETFX_40
Console.WriteLine("NET_40 was set");
#endif
#if NETFX_35
Console.WriteLine("NETFX_35 was set");
#endif
#if NETFX_30
Console.WriteLine("NETFX_30 was set");
#endif
#if NETFX_20
Console.WriteLine("NETFX_20 was set");
#else
The Version specific symbols were not set correctly!
#endif
#if DEBUG
Console.WriteLine("DEBUG was set");
#endif
#if MySymbol
Console.WriteLine("MySymbol was set");
#endif
Console.ReadKey();
}
}
}
在.NET 4.0之前实现Join(字符串定界符,IEnumerable字符串)
// string Join(this IEnumerable<string> strings, string delimiter)
// was not introduced until 4.0. So provide our own.
#if ! NETFX_40 && NETFX_35
public static string Join( string delimiter, IEnumerable<string> strings)
{
return string.Join(delimiter, strings.ToArray());
}
#endif
Can I make a preprocessor directive dependent on the .NET framework version?
Conditional compilation depending on the framework version in C#
答案 2 :(得分:29)
属性组仅会被覆盖,因此会破坏DEBUG
,TRACE
或其他任何设置。 - 见MSBuild Property Evaluation
此外,如果从命令行设置DefineConstants
属性,则在项目文件中对其执行的操作无关紧要,因为该设置将成为全局只读。这意味着您对该值的更改将无提示失败。
维护现有定义常量的示例:
<CustomConstants Condition=" '$(TargetFrameworkVersion)' == 'v2.0' ">V2</CustomConstants>
<CustomConstants Condition=" '$(TargetFrameworkVersion)' == 'v4.0' ">V4</CustomConstants>
<DefineConstants Condition=" '$(DefineConstants)' != '' And '$(CustomConstants)' != '' ">$(DefineConstants);</DefineConstants>
<DefineConstants>$(DefineConstants)$(CustomConstants)</DefineConstants>
此部分必须遵循任何其他定义的常量,因为这些常量不可能以相加的方式设置
我只定义了那些2,因为这主要是我对我的项目感兴趣的,ymmv。
答案 3 :(得分:5)
我想提供更新的答案,以解决一些问题。
如果设置DefineConstants而不是CustomConstants,那么在条件编译符号调试命令行中,在一些框架版本切换后,使用重复的条件常量(即:NETFX_451; NETFX_45; NETFX_40; NETFX_35; NETFX_30; NETFX_20; NETFX_35; NETFX_30; NETFX_20)。 这是VersionSpecificSymbols.Common.prop,可以解决任何问题。
<!--
*********************************************************************
Defines the Compile time symbols Microsoft forgot
Modelled from https://msdn.microsoft.com/en-us/library/ms171464.aspx
*********************************************************************
Author: Lorenzo Ruggeri (lrnz.ruggeri@gmail.com)
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Choose>
<When Condition=" $(TargetFrameworkVersion) == 'v2.0' ">
<PropertyGroup>
<CustomConstants >$(CustomConstants);NETFX_20</CustomConstants>
</PropertyGroup>
</When>
<When Condition=" $(TargetFrameworkVersion) == 'v3.0' ">
<PropertyGroup>
<CustomConstants >$(CustomConstants);NETFX_30</CustomConstants>
<CustomConstants >$(CustomConstants);NETFX_20</CustomConstants>
</PropertyGroup>
</When>
<When Condition=" $(TargetFrameworkVersion) == 'v3.5' ">
<PropertyGroup>
<CustomConstants >$(CustomConstants);NETFX_35</CustomConstants>
<CustomConstants >$(CustomConstants);NETFX_30</CustomConstants>
<CustomConstants >$(CustomConstants);NETFX_20</CustomConstants>
</PropertyGroup>
</When>
<Otherwise>
<PropertyGroup>
<CustomConstants Condition="$([System.Version]::Parse('$(TargetFrameworkVersion.Substring(1))').CompareTo($([System.Version]::Parse('4.5.1')))) >= 0">$(CustomConstants);NETFX_451</CustomConstants>
<CustomConstants Condition="$([System.Version]::Parse('$(TargetFrameworkVersion.Substring(1))').CompareTo($([System.Version]::Parse('4.5')))) >= 0">$(CustomConstants);NETFX_45</CustomConstants>
<CustomConstants Condition="$([System.Version]::Parse('$(TargetFrameworkVersion.Substring(1))').CompareTo($([System.Version]::Parse('4.0')))) >= 0">$(CustomConstants);NETFX_40</CustomConstants>
<CustomConstants Condition="$([System.Version]::Parse('$(TargetFrameworkVersion.Substring(1))').CompareTo($([System.Version]::Parse('3.5')))) >= 0">$(CustomConstants);NETFX_35</CustomConstants>
<CustomConstants Condition="$([System.Version]::Parse('$(TargetFrameworkVersion.Substring(1))').CompareTo($([System.Version]::Parse('3.0')))) >= 0">$(CustomConstants);NETFX_30</CustomConstants>
<CustomConstants Condition="$([System.Version]::Parse('$(TargetFrameworkVersion.Substring(1))').CompareTo($([System.Version]::Parse('2.0')))) >= 0">$(CustomConstants);NETFX_20</CustomConstants>
</PropertyGroup>
</Otherwise>
</Choose>
<PropertyGroup>
<DefineConstants>$(DefineConstants);$(CustomConstants)</DefineConstants>
</PropertyGroup>
</Project>
答案 4 :(得分:5)
目标框架的预定义符号现已构建到dotnet
工具和VS 2017以后使用的MSBuild版本中。有关完整列表,请参阅https://docs.microsoft.com/en-us/dotnet/standard/frameworks#how-to-specify-target-frameworks。
#if NET47
Console.WriteLine("Running on .Net 4.7");
#elif NETCOREAPP2_0
Console.WriteLine("Running on .Net Core 2.0");
#endif
答案 5 :(得分:1)
使用反射来确定类是否存在。如果是,则动态创建并使用它,否则使用可以定义但不用于所有其他.net版本的.Net2解决方法类。
以下是我用于AggregateException
的代码,仅用于.Net 4及更高版本:
var aggregatException = Type.GetType("System.AggregateException");
if (aggregatException != null) // .Net 4 or greater
{
throw ((Exception)Activator.CreateInstance(aggregatException, ps.Streams.Error.Select(err => err.Exception)));
}
// Else all other non .Net 4 or less versions
throw ps.Streams.Error.FirstOrDefault()?.Exception
?? new Exception("Powershell Exception Encountered."); // Sanity check operation, should not hit.