22 Stimmen

Ist es möglich, bedingt nach der .NET Framework Version zu kompilieren?

Ich kann mich erinnern, dass man bei der Arbeit mit MFC mehrere Versionen des MFC-Frameworks unterstützen konnte, indem man die _MFC_VER Makro.

Ich tue einige Sachen jetzt mit .NET 4 und möchte Tuple in ein paar Punkten zu verwenden, aber immer noch alles andere 3.5 kompatibel zu halten.

Ich möchte so etwas machen wie:

#if DOTNET4
    public Tuple<TSource, TResult> SomeMethod<TSource, TResult>(){...}
#else
    public KeyValuePair<TSource, TResult> SomeMethod<TSource, TResult>(){...}
#endif

12voto

Kevinoid Punkte 2960

Wenn Sie das .NET Core-Build-System verwenden, können Sie dessen vordefinierte Symbole nutzen:

#if NET40
    public Tuple<TSource, TResult> SomeMethod<TSource, TResult>(){...}
#else
    public KeyValuePair<TSource, TResult> SomeMethod<TSource, TResult>(){...}
#endif

Die Liste der vordefinierten Symbole ist dokumentiert in Entwicklung von Bibliotheken mit plattformübergreifenden Tools y #if (C# Referenz) :

.NET Framework: NETFRAMEWORK , NET48 , NET472 , NET471 , NET47 , NET462 , NET461 , NET46 , NET452 , NET451 , NET45 , NET40 , NET35 , NET20

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

.NET 5+ (und .NET Core): NET , NET6_0 , NET6_0_ANDROID , NET6_0_IOS , NET6_0_MACOS , NET6_0_MACCATALYST , NET6_0_TVOS , NET6_0_WINDOWS , NET5_0 , NETCOREAPP , NETCOREAPP3_1 , NETCOREAPP3_0 , NETCOREAPP2_2 , NETCOREAPP2_1 , NETCOREAPP2_0 , NETCOREAPP1_1 , NETCOREAPP1_0

11voto

rmiesen Punkte 2450

Bei der Definition von benutzerdefinierten Kompilierungssymbolen in Ihrer .csproj (oder .vbproj, theoretisch) ist eine große Einschränkung zu beachten: Sie überschreiben alle zuvor definierten Kompilierungssymbole. Betrachten Sie zum Beispiel das MSBuild-Snippet:

  <PropertyGroup Condition="'$(TargetFrameworkVersion)' == 'v4.0'">
    <DefineConstants>$(DefineConstants);DOTNET_40</DefineConstants>
  </PropertyGroup>
  <PropertyGroup>
    <DefineConstants>ITS_CLOBBERING_TIME</DefineConstants>
  </PropertyGroup>

Das zweite DefineConstants-Element wird, wie sein Wert vermuten lässt, den ersten Wert von DefineConstants überlagern. Um dies zu vermeiden, sollten Sie das zweite DefineConstants-Element so umschreiben, dass es wie folgt aussieht:

    <DefineConstants>$(DefineConstants);ITS_CLOBBERING_TIME</DefineConstants>

Außerdem sollten Sie dies innerhalb einer PropertyGroup platzieren, die wie folgt definiert ist nach alle anderen PropertyGroups, wie Visual Studio 2010 fügt derzeit in benutzerdefinierte Kompilierungssymbole in einer solchen Weise, dass es alle anderen benutzerdefinierten Kompilierungssymbole, die Sie definieren, wenn sie platziert werden, bevor Visual Studio seine Definition plumpsen wird clobber. Ich habe dieses Problem bei Microsoft eingereicht. Sie können den Fortschritt verfolgen unter Microsoft Verbinden .

7voto

Brian Gideon Punkte 46450

Es gibt keine eingebauten Precompiler-Konstanten, die Sie verwenden können. Aber es ist einfach genug, eigene Build-Konfigurationen in VS zu erstellen, wobei jede Konfiguration ihren eigenen Satz definierter Konstanten und natürlich eine Ziel-Framework-Version hat. Viele Leute tun dies, um bedingte Kompilierung basierend auf 32 oder 64 Bit Unterschiede.

7voto

Doug Punkte 4870

Nebenbei bemerkt: Ihr Code für die bedingte Kompilierung wird die Programmierer, die darauf stoßen, frustrieren.

Bearbeitet, aufgrund von Kommentaren

Es ist wahrscheinlich besser, Ihre eigene Klasse zu schreiben, damit Sie garantieren können, was sie tun wird, und Sie haben keine seltsamen Signatur- oder Vererbungsprobleme:

public class Pair<TSource, TResult>
{
    public TSource Source { get; set; }
    public TResult Result { get; set; }

    public Pair() {}
    public Pair(TSource source, TResult result)
    {
        Source = source;
        Result = result;
    }

    // Perhaps override Equals() and GetHashCode() as well
}

Wie immer ist es gut abzuwägen, ob man die eingebauten Funktionen nutzt oder seinen eigenen Code entwickelt. Im Allgemeinen bedeutet das, dass Sie sich fragen: "Ist es für mich in Ordnung, diesen Code zu pflegen und zu unterstützen?" im Gegensatz zu "Erfüllt der Code die Anforderungen, die ich an ihn stelle?"

Da in diesem Fall nicht garantiert werden kann, dass Sie Tuple<T1, T2> Ich würde einfach ein eigenes, einfaches Programm schreiben, damit andere Entwickler aufatmen können :)

1voto

Mr.O Punkte 37

Da Sie verschiedene Projekte haben sollten, könnten Sie partielle Klassen haben und nur auf diejenige verweisen, die Sie für jedes Projekt mit der spezifischen Logik für sie benötigen:

klassenname.cs public partial classname { ... }

klassenname.40.cs public partial classname { public Tupel SomeMethod(){...} }

klassenname.35.cs public partial classname { public KeyValuePair SomeMethod(){...} }

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X