컴파일 타임에 대상 프레임 워크 버전 감지
확장 메서드를 사용하는 코드가 있지만 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를 포함하는 데 사용할 수있는 컴파일 시간 지시문이 있습니까?
'N 개의 다른 구성 만들기'와 연결된 SO 질문은 확실히 하나의 옵션이지만 이것이 필요했을 때 조건부 DefineConstants 요소를 추가했기 때문에 DEBUG; TRACE에 대한 기존 DefineConstants 뒤에 Debug | x86 (예를 들어)에서, 이 2를 추가하여 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을 대상으로 전환하면 올바른 작업을 수행 할 수 있습니다.
지금까지 제공된 답변을 개선하기위한 몇 가지 제안이 있습니다.
Version.CompareTo ()를 사용하십시오. 동등성 테스트는 이후 프레임 워크 버전에서 작동하지 않지만 아직 이름이 지정되지 않았습니다. 예
<CustomConstants Condition=" '$(TargetFrameworkVersion)' == 'v4.0' ">
일반적으로 원하는 v4.5 또는 v4.5.1과 일치하지 않습니다.
이러한 추가 속성을 한 번만 정의하면되도록 가져 오기 파일을 사용합니다. 추가 노력없이 변경 사항이 프로젝트 파일과 함께 전파되도록 가져 오기 파일을 소스 제어 상태로 유지하는 것이 좋습니다.
프로젝트 파일 끝에 import 요소를 추가하여 구성 별 속성 그룹과 독립적입니다. 이것은 또한 프로젝트 파일에 단일 추가 라인이 필요한 이점이 있습니다.
다음은 가져 오기 파일 (VersionSpecificSymbols.Common.prop)입니다.
<!--
******************************************************************
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#
Property groups are overwrite only so this would knock out your settings for DEBUG
, TRACE
, or any others. - See MSBuild Property Evaluation
Also if the DefineConstants
property is set from the command line anything you do to it inside the project file is irrelevant as that setting becomes global readonly. This means your changes to that value fail silently.
Example maintaining existing defined constants:
<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>
This section MUST come after any other defined constants since those are unlikely to be set up in an additive manner
I only defined those 2 because that's mostly what I'm interested in on my project, ymmv.
See Also: Common MsBuild Project Properties
I would like to contribute with an updated answer which solves some issues.
If you set DefineConstants instead of CustomConstants you'll end up, in the Conditional Compilation Symbols Debug command line, after some framework version switch, with duplicated conditional constants (i.e.: NETFX_451;NETFX_45;NETFX_40;NETFX_35;NETFX_30;NETFX_20;NETFX_35;NETFX_30;NETFX_20;). This is the VersionSpecificSymbols.Common.prop which solves any issue.
<!--
*********************************************************************
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>
Pre-defined symbols for target frameworks are now built into the version of MSBuild that is used by the dotnet
tool and by VS 2017 onwards. See https://docs.microsoft.com/en-us/dotnet/standard/frameworks#how-to-specify-target-frameworks for the full list.
#if NET47
Console.WriteLine("Running on .Net 4.7");
#elif NETCOREAPP2_0
Console.WriteLine("Running on .Net Core 2.0");
#endif
Use reflection to determine if the class exists. If it does, then dynamically create and use it, otherwise use the .Net2 workaround class which can be defined, but not used for all other .net versions.
Here is code I used for an AggregateException
which is .Net 4 and greater only:
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.
ReferenceURL : https://stackoverflow.com/questions/3436526/detect-target-framework-version-at-compile-time
'IT박스' 카테고리의 다른 글
플래그가있는 Python re.sub가 모든 발생을 대체하지는 않습니다. (0) | 2020.12.29 |
---|---|
Matplotlib : 축 색상 변경 (0) | 2020.12.29 |
HTML 선택 컨트롤에 수평선을 어떻게 추가합니까? (0) | 2020.12.29 |
모든 ivar는 재산이어야합니까? (0) | 2020.12.29 |
RegExp 개체에 정규식 수정 자 옵션 전달 (0) | 2020.12.29 |