Détection de la version cible du framework au moment de la compilation

j'ai du code qui utilise des méthodes D'Extension, mais qui se compile sous .NET 2.0 en utilisant le compilateur dans VS2008. Pour faciliter cela, j'ai dû déclarer ExtensionAttribute:

/// <summary>
/// ExtensionAttribute is required to define extension methods under .NET 2.0
/// </summary>
public sealed class ExtensionAttribute : Attribute
{
}

cependant, je voudrais maintenant que la bibliothèque dans laquelle cette classe est contenue soit aussi compilable sous .NET 3.0, 3.5 et 4.0 - sans 'ExtensionAttribute est défini dans l'avertissement de plusieurs endroits'.

Existe-t-il une directive de compilation que je ne peux utiliser inclure L'ExtensionAttribute lorsque la version de cadre visée est .NET 2?

55
demandé sur denfromufa 2010-08-09 03:42:35

6 réponses

la question liée SO avec 'create N different configurations' est certainement une option, mais quand j'en avais besoin j'ai juste ajouté des éléments conditionnels DefineConstants, donc dans mon Debug|x86 (par exemple) après les DefineConstants existants pour DEBUG;TRACE, j'ai ajouté ces 2, en vérifiant la valeur dans TFV qui a été définie dans le premier groupe de propriété du fichier csproj.

<DefineConstants Condition=" '$(TargetFrameworkVersion)' == 'v4.0' ">RUNNING_ON_4</DefineConstants>
<DefineConstants Condition=" '$(TargetFrameworkVersion)' != 'v4.0' ">NOT_RUNNING_ON_4</DefineConstants>

vous n'avez pas besoin des deux, évidemment, mais il est juste là pour donner des exemples de deux eq et ne de comportement - #else et #elif travail trop belle :)

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

je pourrais alors passer du ciblage 3.5 au 4.0 et ça ferait la bonne chose.

59
répondu James Manning 2010-08-09 03:58:08

les groupes de propriétés sont écrasés seulement de sorte que cela détruirait vos paramètres pour DEBUG , TRACE , ou tout autre. - Voir Évaluation De La Propriété De MSBuild

aussi si la propriété DefineConstants est définie à partir de la ligne de commande, Tout ce que vous faites à l'intérieur du fichier du projet n'est pas pertinent car ce paramètre devient global en lecture seule. Cela signifie que vos modifications à cette valeur échouent silencieusement.

exemple de maintien constantes définies:

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

cette section doit être suivie de toute autre constante définie puisqu'il est peu probable qu'elle soit établie de façon additive

j'ai seulement défini ces 2 parce que c'est surtout ce qui m'intéresse dans mon projet, ymmv.

Voir Aussi: Commune MsBuild Propriétés Du Projet

29
répondu Maslow 2011-02-10 17:09:36

j'ai quelques suggestions pour améliorer les réponses données jusqu'à présent:

  1. Utiliser La Version.CompareTo(). Les essais de l'égalité ne fonctionnera pas pour plus tard versions framework, pas encore nommé. Par exemple:

    <CustomConstants Condition=" '$(TargetFrameworkVersion)' == 'v4.0' ">
    

    ne correspond pas à v4.5 ou v4.5.1, ce que vous voulez typiquement.

  2. utilisez un fichier d'importation de sorte que ces propriétés supplémentaires n'ont besoin d'être définies qu'une seule fois. Je recommande conserver le fichier des importations sous contrôle des sources, de sorte que les changements soient propagés avec les fichiers du projet, sans effort supplémentaire.

  3. ajoutez l'élément import à la fin de votre fichier de projet, de sorte qu'il soit indépendant de tout groupe de propriétés spécifique à la configuration. Cela a également l'avantage d'exiger une seule ligne supplémentaire dans votre dossier de projet.

Voici le fichier d'importation (VersionSpecificSymbols.Commun.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')))) &gt;= 0">$(DefineConstants);NETFX_451</DefineConstants>
        <DefineConstants Condition="$([System.Version]::Parse('$(TargetFrameworkVersion.Substring(1))').CompareTo($([System.Version]::Parse('4.5'))))   &gt;= 0">$(DefineConstants);NETFX_45</DefineConstants>
        <DefineConstants Condition="$([System.Version]::Parse('$(TargetFrameworkVersion.Substring(1))').CompareTo($([System.Version]::Parse('4.0'))))   &gt;= 0">$(DefineConstants);NETFX_40</DefineConstants>
        <DefineConstants Condition="$([System.Version]::Parse('$(TargetFrameworkVersion.Substring(1))').CompareTo($([System.Version]::Parse('3.5'))))   &gt;= 0">$(DefineConstants);NETFX_35</DefineConstants>
        <DefineConstants Condition="$([System.Version]::Parse('$(TargetFrameworkVersion.Substring(1))').CompareTo($([System.Version]::Parse('3.0'))))   &gt;= 0">$(DefineConstants);NETFX_30</DefineConstants>
    </PropertyGroup>
</Project>

Ajouter un élément D'importation au dossier de projet

référence de votre .csproj fichier en ajoutant à la fin, avant la balise.

…
    <Import Project="VersionSpecificSymbols.Common.prop" />
</Project>

vous aurez besoin de corriger le chemin pour pointer vers le dossier commun/partagé où vous placez ce fichier.

Pour Utiliser Les Symboles De Temps De Compilation

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();
        }
    }
}

, Une Commune "La Vraie Vie" Exemple

implémenter Join (délimiteur de chaîne, IEnumerable strings) avant .NET 4.0

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

Références

Fonctions Immobilières

Évaluation De La Propriété De MSBuild

puis-je faire dépendre une directive préprocesseur de la version. NET framework?

compilation conditionnelle selon la version du cadre dans C#

29
répondu Andrew Dennison 2017-05-23 12:34:19

je voudrais contribuer avec une réponse mise à jour qui résout certains problèmes.

si vous définissez DefineConstants à la place de CustomConstants, vous finirez, dans la ligne de commande des symboles de Compilation conditionnelle, après un changement de version du framework, avec des constantes conditionnelles dupliquées (i.e.: NETFX_451;NETFX_45;NETFX_40;NETFX_35;NETFX_30;NETFX_20;NETFX_35;NETFX_30;NETFX_20;). C'est le VersionSpecificSymbols.Commun.un accessoire qui résout tous les problèmes.

<!--
*********************************************************************
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')))) &gt;= 0">$(CustomConstants);NETFX_451</CustomConstants>
        <CustomConstants Condition="$([System.Version]::Parse('$(TargetFrameworkVersion.Substring(1))').CompareTo($([System.Version]::Parse('4.5')))) &gt;= 0">$(CustomConstants);NETFX_45</CustomConstants>
        <CustomConstants Condition="$([System.Version]::Parse('$(TargetFrameworkVersion.Substring(1))').CompareTo($([System.Version]::Parse('4.0')))) &gt;= 0">$(CustomConstants);NETFX_40</CustomConstants>
        <CustomConstants Condition="$([System.Version]::Parse('$(TargetFrameworkVersion.Substring(1))').CompareTo($([System.Version]::Parse('3.5')))) &gt;= 0">$(CustomConstants);NETFX_35</CustomConstants>
        <CustomConstants Condition="$([System.Version]::Parse('$(TargetFrameworkVersion.Substring(1))').CompareTo($([System.Version]::Parse('3.0')))) &gt;= 0">$(CustomConstants);NETFX_30</CustomConstants>
        <CustomConstants Condition="$([System.Version]::Parse('$(TargetFrameworkVersion.Substring(1))').CompareTo($([System.Version]::Parse('2.0')))) &gt;= 0">$(CustomConstants);NETFX_20</CustomConstants>
      </PropertyGroup>
    </Otherwise>
  </Choose>
  <PropertyGroup>
    <DefineConstants>$(DefineConstants);$(CustomConstants)</DefineConstants>
  </PropertyGroup>
</Project>
5
répondu Lorenzo 2016-07-18 21:47:35

les symboles prédéfinis pour les cadres cibles sont maintenant intégrés dans la version de MSBuild qui est utilisée par l'outil dotnet et à partir de VS 2017. Voir https://docs.microsoft.com/en-us/dotnet/standard/frameworks#how-to-specify-target-frameworks pour la liste complète.

#if NET47
Console.WriteLine("Running on .Net 4.7");
#elif NETCOREAPP2_0
Console.WriteLine("Running on .Net Core 2.0");
#endif
3
répondu Arnavion 2018-04-15 04:04:28

Utiliser la réflexion pour déterminer si la classe existe. Si c'est le cas, alors dynamiquement le créer et l'utiliser, sinon utiliser le .Classe de contournement Net2 qui peut être définie, mais pas utilisée pour toutes les autres versions .net.

voici le code que j'ai utilisé pour un AggregateException qui est .Net 4 et plus seulement:

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.
1
répondu ΩmegaMan 2017-03-02 16:38:50