[C#] 조건부 컴파일 및 프레임 워크 대상

대상 프레임 워크가 최신 버전 인 경우 내 프로젝트의 코드를 대폭 개선 할 수있는 사소한 부분이 있습니다. 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>

그리고 기본 구성 중 하나에서 :

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

다른 곳에서 정의되지 않은 경우 기본값을 설정합니다. 위의 경우 OutputPath는 각 버전을 빌드 할 때마다 별도의 어셈블리를 제공합니다.

그런 다음 AfterBuild 대상을 만들어 다른 버전을 컴파일합니다.

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

이 예제는 첫 번째 빌드 후에 Framework 변수를 NET20으로 설정하여 전체 프로젝트를 다시 컴파일합니다 (둘 다 컴파일하고 첫 번째 빌드가 위에서 기본 NET35라고 가정). 각 컴파일에는 조건부 정의 값이 올바르게 설정됩니다.

이러한 방식으로 파일을 #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 속성의 값을 사용하여 “v”및 “.”를 대체합니다. “NET35″를 얻으려면 (새 속성 함수 기능 사용) 그런 다음 기존 “NETxx”값을 제거하고이를 DefinedConstants 끝에 추가합니다. 이것을 능률화하는 것이 가능할 수도 있지만 나는 바이올린을 켤 시간이 없습니다.

VS에서 프로젝트 속성의 빌드 탭을 보면 조건부 컴파일 기호 섹션에 결과 값이 표시됩니다. 애플리케이션 탭에서 대상 프레임 워크 버전을 변경하면 기호가 자동으로 변경됩니다. 그런 다음 #if NETxx일반적인 방법으로 전 처리기 지시문 을 사용할 수 있습니다 . VS에서 프로젝트를 변경해도 사용자 정의 PropertyGroup이 손실되지 않는 것 같습니다.

이것은 Client Profile 대상 옵션에 대해 다른 것을주는 것 같지 않지만 나에게는 문제가되지 않습니다.


답변

초기 상수가 이러한 속성에 의해 미리 만들어 졌기 때문에 이러한 솔루션에 문제가있었습니다.

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

Visual Studio 2010은 세미콜론으로 인해 잘못된 문자라고 주장하는 오류도 발생했습니다. 오류 메시지는 쉼표로 구분 된 미리 빌드 된 상수를 볼 수 있었고 결국 “불법”세미콜론이 뒤 따르는 것을 볼 수 있었기 때문에 힌트를주었습니다. 약간의 재 포맷 및 마사지 후 저에게 맞는 솔루션을 찾을 수있었습니다.

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

고급 컴파일러 설정 대화 상자의 스크린 샷을 게시합니다 (프로젝트의 컴파일 탭에서 “고급 컴파일 옵션 …”버튼을 클릭하여 열림). 그러나 새로운 사용자로서 나는 그렇게 할 담당자가 부족합니다. 스크린 샷을 볼 수 있다면 속성 그룹에 의해 자동으로 채워지는 사용자 지정 상수가 표시되고 “그 중 일부를 가져와야합니다.”라고 말할 것입니다.

편집 : 그 담당자는 놀랍도록 빠르게 .. 감사합니다! 그 스크린 샷은 다음과 같습니다.

고급 컴파일러 설정


답변

상수 지우기로 시작하십시오.

<PropertyGroup>
  <DefineConstants/>
</PropertyGroup>

다음으로 디버그, 추적 및 다음과 같은 기타 상수를 빌드하십시오.

<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
    <DebugSymbols>true</DebugSymbols>
  <DebugType>full</DebugType>
  <Optimize>false</Optimize>
  <DefineConstants>TRACE;DEBUG;$(DefineConstants)</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>

이 접근 방식은 매우 읽기 쉽고 이해하기 쉽습니다.


답변

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

디버그 및 릴리스 빌드 구성 모두에 대해이 작업을 수행하십시오. 그런 다음 코드에서 사용하십시오.

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


답변

@Azarien, 귀하의 답변은 Jeremy와 결합하여 Debug | Release 등이 아닌 한곳에 보관할 수 있습니다.

저에게는 두 변형을 결합하는 것이 가장 잘 작동합니다. 즉 #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>

및 대상 :

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


답변

.NET Core 빌드 시스템을 사용하는 경우 미리 정의 된 기호를 사용할 수 있습니다 (실제로 이미 예제와 일치하며 변경할 필요가 없습니다 .csproj!).

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

미리 정의 된 기호 목록은 크로스 플랫폼 도구#if (C # 참조)를 사용 하여 라이브러리 개발에 설명되어 있습니다 .

.NET 프레임 워크 : NETFRAMEWORK , NET20, NET35, NET40, NET45, NET451, NET452, NET46, NET461, NET462, NET47, NET471, NET472,NET48

.NET 표준 : NETSTANDARD , NETSTANDARD1_0, NETSTANDARD1_1, NETSTANDARD1_2, NETSTANDARD1_3, NETSTANDARD1_4, NETSTANDARD1_5, NETSTANDARD1_6, NETSTANDARD2_0,NETSTANDARD2_1

.NET 코어 : NETCOREAPP , NETCOREAPP1_0, NETCOREAPP1_1, NETCOREAPP2_0, NETCOREAPP2_1, NETCOREAPP2_2,NETCOREAPP3_0