2010-05-27 1 views
114

Есть несколько второстепенных мест, где код для моего проекта может быть значительно улучшен, если целевая структура была более новой версией. Я хотел бы иметь возможность лучше использовать условную компиляцию на C#, чтобы переключать их по мере необходимости.Условная компиляция и целевые значения рамок

Что-то вроде:

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

любой из этих символов прийти бесплатно? Нужно ли вводить эти символы в качестве части конфигурации проекта? Кажется, достаточно легко сделать, так как я буду знать, какие рамки нацелены на MSBuild.

/p:DefineConstants="NET40" 

Update: Мой вопрос заключается в том, как люди обработки этой ситуации? Вы создаете разные конфигурации? Вы передаете константы через командную строку?

+1

Возможный дубликат [Можно условно скомпилировать версию .NET Framework?] (Http://stackoverflow.com/questions/1449925/is-it-possible-to-condition-compile-to-net-framework -версия) – JohnC

+0

Если вы хотите простое предварительное испрошенное решение в VS, пожалуйста, проголосуйте за этот голос пользователя, http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/7699920-built-in-conditional -compilation-на-каркасных-вар. – JohnC

+1

Взгляните на эту ссылку. Довольно объяснительный. http://blogs.msmvps.com/punitganshani/2015/06/21/5-steps-to-targeting-multiple-net-frameworks/ –

ответ

112

Один из лучших способов сделать это состоит в создании различных конфигураций сборки в проекте:

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

Этот пример будет перекомпилировать весь проект с Рамочной переменной, заданной в 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> 
+0

Отлично. У меня было достаточно опыта взломать формат msbuild, чтобы знать, что это можно сделать, но недостаточно времени, чтобы выяснить все детали. Большое спасибо! – mckamey

+0

Если вы добавите ссылку на этот ответ по моему связанному вопросу (http://stackoverflow.com/questions/2923181), я помечаю вас как решение там. Это фактически решает оба из них в одно и то же время. – mckamey

+7

Спасибо за ответ, но теперь VS2010 уже включает новый тег с именем «TargetFrameworkVersion», теперь для каждой группы свойств с условием изменяется только TargetFrameworkVersion, нужно ли нам все это сделать, чтобы заставить его работать? –

41

альтернатива, работает до сих пор, заключается в добавлении к файлу проекта следующего содержания:

<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, которое похоже на «v3.5», заменяет «v» и «.». для получения «NET35» (с использованием новой функции Property Functions). Затем он удаляет любое существующее значение «NETxx» и добавляет его в конец DefinedConstants. Возможно, это будет возможно, но у меня нет времени на скрипку.

Глядя на вкладку «Сборка» свойств проекта в VS, вы увидите результирующее значение в разделе условных компиляций. Изменение версии целевой структуры на вкладке «Приложение» автоматически изменяет символ. Затем вы можете использовать директивы препроцессора #if NETxx обычным способом. Изменение проекта в VS не похоже на пользовательскую PropertyGroup.

Обратите внимание, что это не дает вам ничего другого для целевых параметров профиля клиента, но это не проблема для меня.

+0

Джереми, ничего себе, спасибо, что это прекрасно, поскольку я уже строил отдельно в своем построить решение. –

+0

+1. Кто бы мог подумать, что было бы так сложно найти «$ (DefineConstants.Contains (« ... »?? Спасибо –

+0

+1 Хорошее решение! =) – 2013-05-21 15:02:57

2

В файле .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 
+3

параметры по умолчанию и именованные параметры не являются признаком .NET framework 4, а являются особенностью компилятора .NET 4. Они также могут использоваться в проекты, ориентированные на .NET 2 или .NET 3, до тех пор, пока они компилируются в Visual Studio 2010. Это просто синтаксический сахар. С другой стороны, динамическая функция .NET Framework 4, и вы не можете использовать его в проектах, ориентированных на рамки до этого. –

2

@Azarien, ваш ответ может быть объединено с Джереми, чтобы держать его на одном месте, а не 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> 
12

У меня были проблемы с этими решениями, возможно, потому, что мои начальные константы были предварительно построенные этими свойствами ,

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

Я бы опубликовать скриншот диалогового окна Advanced Settings Compiler (открыть, нажав на кнопку «Дополнительные опции компиляции ...» на вкладке Compile вашего проекта). Но, как новый пользователь, мне не хватает репутации для этого. Если бы вы могли увидеть скриншот, вы увидите, что пользовательские константы будут автоматически заполнены группой свойств, а затем вы скажете: «Мне нужно получить некоторые из них».


EDIT: Получили, что репутация на удивление быстро .. Спасибо, ребята! Вот что скриншот:

Advanced Compiler Settings

3

Начните с очисткой константы:

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

Я думаю, что этот подход очень читабельен и понятен.

Смежные вопросы