Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Obwohl der Compiler keinen separaten Präprozessor hat, werden die in diesem Abschnitt beschriebenen Anweisungen verarbeitet, als gäbe es einen. Sie werden zur Unterstützung der bedingten Kompilierung verwendet. Sie können diese Anweisungen im Gegensatz zu C- und C++-Anweisungen nicht verwenden, um Makros zu erstellen. Eine Präprozessordirektive muss die einzige Anweisung in einer Zeile sein.
Dateibasierte Apps
Dateibasierte Apps sind Programme , die kompiliert und mit dotnet run Program.cs einer beliebigen *.cs Datei ausgeführt werden. Der C#-Compiler ignoriert diese Präprozessordirektiven, aber das Buildsystem analysiert sie, um die Ausgabe zu erzeugen. Diese Direktiven generieren Warnungen, wenn sie in einer projektbasierten Kompilierung auftreten.
Der C#-Compiler ignoriert jede Präprozessordirektive, die mit #: oder #! beginnt.
Die #! Präprozessordirektive ermöglicht Unix-Shells die direkte Ausführung einer C#-Datei mithilfe von dotnet run. Zum Beispiel:
#!/usr/bin/env dotnet run
Console.WriteLine("Hello");
Der vorangehende Codeausschnitt weist eine Unix-Shell an, die Datei mit dotnet run auszuführen. Der /usr/bin/env Befehl sucht die dotnet ausführbare Datei in Ihrem PATH und macht diesen Ansatz in verschiedenen Unix- und macOS-Verteilungen portierbar. Die #! Zeile muss die erste Zeile in der Datei sein, und die folgenden Token sind das auszuführende Programm. Sie müssen die Ausführungsberechtigung (x) für die C#-Datei für dieses Feature aktivieren.
Zu #: den Direktiven, die in dateibasierten Apps verwendet werden, gehören:
#:sdk:Die erste Instanz gibt den Wert für den
<Project Sdk="value" />Knoten an. Nachfolgende Instanzen geben den<Sdk Name="value" Version="version" />Knoten an. Die Version kann weggelassen werden (d. h. wenn in global.json angegeben oder in .NET SDK enthalten). Zum Beispiel:#:sdk Microsoft.NET.Sdk.Web #:sdk Aspire.AppHost.Sdk@9.4.1Die beiden vorangehenden Präprozessoren werden übersetzt in:
<Project Sdk="Microsoft.NET.Sdk.Web" /> <Sdk Name="Aspire.AppHost.Sdk" Version="9.4.1" />#:property:Instanzen von
#:propertywerden als Eigenschaftselemente in einem<PropertyGroup>übersetzt. Ein Token des FormularsName=valuemuss dempropertyToken folgen. Die folgenden Beispieldirektiven sind gültigepropertyToken:#:property TargetFramework=net11.0 #:property LangVersion=previewDie beiden vorherigen Eigenschaften werden übersetzt in:
<TargetFramework>net11.0</TargetFramework> <LangVersion>preview</LangVersion>#:package:Instanzen von
#:packagewerden inPackageReferenceElemente übersetzt, um NuGet-Pakete mit der angegebenen Version in Ihre Datei einzuschließen. Zum Beispiel:#:package System.CommandLine@2.0.0-*Das vorangehende Präprozessortoken wird übersetzt in:
<PackageReference Include="System.CommandLine" Version="2.0.0-*">#:project:Instanzen von
#:projectwerden inProjectReferenceElemente übersetzt, um das Projekt mit dem angegebenen Pfad zum Projekt einzuschließen. Zum Beispiel:#:project ../Path/To.ExampleDas vorangehende Präprozessortoken wird übersetzt in:
<ProjectReference Include="../Path/To.Example/To.Example.csproj" />
Tools können nach der #: Konvention neue Token hinzufügen.
Nullwerte zulassender Kontext
Die #nullable-Präprozessoranweisung setzt die Anmerkungs- und Warnungsflags im Null-Wert-fähigen Kontext. Die Anweisung steuert, ob Nullable-Anmerkungen wirksam sind und ob Warnungen zur NULL-Zulässigkeit angegeben werden. Jedes Flag ist entweder deaktiviert oder aktiviert.
Beide Kontexte können auf Projektebene (außerhalb des C#-Quellcodes) angegeben werden, indem das Nullable Element dem PropertyGroup Element hinzugefügt wird. Die #nullable-Anweisung steuert die Anmerkungs- und Warnungsflags und hat Vorrang vor anderen Einstellungen auf Projektebene. Eine Anweisung legt das von ihr gesteuerte Flag fest, bis sie von einer anderen Anweisung überschrieben wird oder bis zum Ende der Quelldatei.
Die Auswirkungen der Anweisungen lauten wie folgt:
-
#nullable disable: Legt den nullfähigen Kontext auf deaktiviert fest. -
#nullable enable: Legt den nullfähigen Kontext auf aktiviert fest. -
#nullable restore: Stellt den nullfähigen Warnungskontext auf Projekteinstellungen wieder her. -
#nullable disable annotations: Setzt das Anmerkungsflag im nullfähigen Kontext auf deaktiviert. -
#nullable enable annotations: Setzt das Anmerkungsflag im nullfähigen Kontext auf aktiviert. -
#nullable restore annotations: Stellt das Anmerkungsflag im nullfähigen Kontext auf Projekteinstellungen wieder her. -
#nullable disable warnings: Setzt das Warnungsflag im nullfähigen Kontext auf deaktiviert. -
#nullable enable warnings: Setzt das Warnungsflag im nullfähigen Kontext auf aktiviert. -
#nullable restore warnings: Stellt da Warnungsflag im nullfähigen Kontext auf die Projekteinstellungen wieder her.
Bedingte Kompilierung
Die bedingte Kompilierung wird über die folgenden vier Präprozessoranweisungen gesteuert:
-
#if: Öffnet eine bedingte Kompilierung, bei der Code nur dann kompiliert wird, wenn das angegebene Symbol definiert ist. -
#elif: Schließt die vorangehende bedingte Kompilierung und öffnet eine neue bedingte Kompilierung, wenn das angegebene Symbol definiert ist. -
#else: Schließt die vorangehende bedingte Kompilierung und öffnet eine neue bedingte Kompilierung, wenn das angegebene Symbol nicht definiert ist. -
#endif: Schließt die vorangehende bedingte Kompilierung.
Das Buildsystem kennt zudem vordefinierte Präprozessorsymbole, die verschiedene Zielframeworks in Projekten im SDK-Format darstellen. Diese sind hilfreich, wenn Sie Anwendungen erstellen, die für mehr als eine .NET-Version bestimmt sind.
| Zielframeworks | Sonderzeichen | Zusätzliche Symbole (verfügbar in SDKs für .NET 5 und höher) |
Plattformsymbole (nur verfügbar, wenn Sie einen betriebssystemspezifischen TFM angeben) |
|---|---|---|---|
| .NET Framework |
NETFRAMEWORK, NET481, , NET48, NET472, NET471, NET47NET462NET461NET46NET452NET451NET45NET40NET35NET20 |
NET48_OR_GREATER, NET472_OR_GREATER, , NET471_OR_GREATER, NET47_OR_GREATER, NET462_OR_GREATERNET461_OR_GREATER, NET46_OR_GREATER, , NET452_OR_GREATER, NET451_OR_GREATER, , NET45_OR_GREATERNET40_OR_GREATER, , NET35_OR_GREATERNET20_OR_GREATER |
|
| .NET-Standard |
NETSTANDARD, NETSTANDARD2_1, , NETSTANDARD2_0NETSTANDARD1_6, NETSTANDARD1_5, NETSTANDARD1_4, NETSTANDARD1_3, , , NETSTANDARD1_2, , NETSTANDARD1_1NETSTANDARD1_0 |
NETSTANDARD2_1_OR_GREATER, NETSTANDARD2_0_OR_GREATER, , NETSTANDARD1_6_OR_GREATERNETSTANDARD1_5_OR_GREATER, NETSTANDARD1_4_OR_GREATER, NETSTANDARD1_3_OR_GREATER, NETSTANDARD1_2_OR_GREATER, , NETSTANDARD1_1_OR_GREATERNETSTANDARD1_0_OR_GREATER |
|
| .NET 5 oder höher (und .NET Core) |
NET, NET10_0, , NET9_0, NET8_0, NET7_0, NET6_0NET5_0NETCOREAPPNETCOREAPP3_1NETCOREAPP3_0NETCOREAPP2_2NETCOREAPP2_1NETCOREAPP2_0NETCOREAPP1_1NETCOREAPP1_0 |
NET10_0_OR_GREATER, NET9_0_OR_GREATER, , NET8_0_OR_GREATER, NET7_0_OR_GREATER, NET6_0_OR_GREATERNET5_0_OR_GREATER, NETCOREAPP3_1_OR_GREATER, , NETCOREAPP3_0_OR_GREATER, NETCOREAPP2_2_OR_GREATER, , NETCOREAPP2_1_OR_GREATERNETCOREAPP2_0_OR_GREATER, , NETCOREAPP1_1_OR_GREATERNETCOREAPP1_0_OR_GREATER |
ANDROID, BROWSER, IOS, MACCATALYST, MACOS, TVOS, WINDOWS[OS][version] (Beispiel: IOS15_1),[OS][version]_OR_GREATER (Beispiel: IOS15_1_OR_GREATER) |
Hinweis
- Versionslose Symbole werden unabhängig von der Version definiert, die Sie als Ziel verwenden.
- Versionsspezifische Symbole werden nur für die Version definiert, die Sie als Ziel verwenden.
- Die
<framework>_OR_GREATER-Symbole werden für die Zielversion und alle früheren Versionen definiert. Wenn Sie beispielsweise .NET Framework 2.0 als Ziel festgelegt haben, werden die folgenden Symbole definiert:NET20,NET20_OR_GREATER,NET11_OR_GREATERundNET10_OR_GREATER. - Die
NETSTANDARD<x>_<y>_OR_GREATER-Symbole werden nur für .NET Standard-Ziele definiert und nicht für Ziele, die .NET Standard implementieren, z. B. .NET Core und .NET Framework. - Diese unterscheiden sich von den Zielframeworkmonikern (TFMs), die von der
TargetFramework-Eigenschaft von MSBuild und NuGet verwendet werden.
Hinweis
Für herkömmliche Projekte, die kein SDK-Format aufweisen, müssen Sie die Symbole für die bedingte Kompilierung für die verschiedenen Zielframeworks in Visual Studio über die Eigenschaftenseite des Projekts manuell konfigurieren.
Andere vordefinierte Symbole beinhalten die Konstanten DEBUG und TRACE. Sie können die für das Projekt festgelegten Werte mit #define überschreiben. Das DEBUG-Symbol beispielsweise wird abhängig von den Buildkonfigurationseigenschaften (Modus „Debug“ oder „Release“) automatisch festgelegt.
Der C#-Compiler kompiliert den Code zwischen der #if-Anweisung und der #endif-Anweisung nur, wenn das angegebene Symbol definiert bzw. bei Verwendung des Nicht-Operators ! nicht definiert ist. Im Gegensatz zu C und C++ kann einem Symbol kein numerischer Wert zugewiesen werden. Die #if-Anweisung in C# ist eine boolesche und testet nur, ob das Symbol definiert ist oder nicht. Beispielsweise wird der folgende Code kompiliert, wenn DEBUG definiert ist:
#if DEBUG
Console.WriteLine("Debug version");
#endif
Der folgende Code wird kompiliert, wenn MYTESTnicht definiert ist:
#if !MYTEST
Console.WriteLine("MYTEST is not defined");
#endif
Sie können die Operatoren == (Gleichheit) und != (Ungleichheit) zum Testen auf die bool-Werte true oder false verwenden.
true bedeutet, dass das Symbol definiert wurde. Die #if DEBUG-Anweisung hat die gleiche Bedeutung wie #if (DEBUG == true). Sie können die Operatoren && (und), || (oder) und ! (not) verwenden, um auszuwerten, ob mehrere Symbole definiert wurden. Symbole und Operatoren können auch mit Klammern gruppiert werden.
Das folgende Beispiel zeigt eine komplexe Direktive, mit der Ihr Code neuere .NET-Features nutzen kann, während sie abwärtskompatibel bleiben. Angenommen, Sie verwenden ein NuGet-Paket in Ihrem Code, aber das Paket unterstützt nur .NET 6 und aufwärts, sowie .NET Standard 2.0 und aufwärts:
#if (NET6_0_OR_GREATER || NETSTANDARD2_0_OR_GREATER)
Console.WriteLine("Using .NET 6+ or .NET Standard 2+ code.");
#else
Console.WriteLine("Using older code that doesn't support the above .NET versions.");
#endif
Wenn Sie #if mit den Direktiven #else, #elif, #endif, #define und #undef verwenden, können Sie Code je nach dem Vorhandensein eines oder mehrerer Symbole ein- oder ausschließen. Die bedingte Kompilierung kann hilfreich sein, wenn Code für einen Debugbuild oder für eine bestimmte Konfiguration kompiliert wird.
Mit #elif können zusammengesetzte bedingte Direktiven erstellt werden. Der #elif-Ausdruck wird ausgewertet, wenn weder der Ausdruck der vorangehenden #if-Anweisung noch der Ausdruck einer vorangehenden (optionalen) #elif-Anweisung als true ausgewertet wird. Wird ein #elif-Ausdruck als true ausgewertet, wird der gesamte Code zwischen der #elif-Anweisung und der nächsten bedingten Anweisung vom Compiler ausgewertet. Zum Beispiel:
#define VC7
//...
#if DEBUG
Console.WriteLine("Debug build");
#elif VC7
Console.WriteLine("Visual Studio 7");
#endif
Mit #else können Sie eine zusammengesetzte bedingte Anweisung erstellen, sodass der Compiler, wenn keiner der Ausdrücke in den vorangehenden #if-Anweisungen oder (optional) #elif-Anweisungen als true ausgewertet wird, den gesamten Code zwischen #else und der nächsten #endif-Anweisung auswertet.
#endif(#endif) muss die nächste Präprozessoranweisung nach #else sein.
#endif gibt das Ende einer bedingten Anweisung an, die mit der #if-Anweisung beginnt.
Im folgenden Beispiel wird gezeigt, wie Sie ein MYTEST-Symbol für eine Datei definieren und dann die Werte der Symbole MYTEST und DEBUG testen. Die Ausgabe dieses Beispiels hängt davon ab, ob Sie das Projekt im Konfigurationsmodus Debug oder Release erstellen.
#define MYTEST
using System;
public class MyClass
{
static void Main()
{
#if (DEBUG && !MYTEST)
Console.WriteLine("DEBUG is defined");
#elif (!DEBUG && MYTEST)
Console.WriteLine("MYTEST is defined");
#elif (DEBUG && MYTEST)
Console.WriteLine("DEBUG and MYTEST are defined");
#else
Console.WriteLine("DEBUG and MYTEST are not defined");
#endif
}
}
Im folgenden Beispiel wird gezeigt, wie für andere Zielframeworks zu testen, damit Sie neuere APIs möglichst verwenden können:
public class MyClass
{
static void Main()
{
#if NET40
WebClient _client = new WebClient();
#else
HttpClient _client = new HttpClient();
#endif
}
//...
}
Definieren von Symbolen
Mit den folgenden beiden Präprozessoranweisungen können Sie Symbole für die bedingte Kompilierung definieren oder eine Definition aufheben:
-
#define: Definiert ein Symbol. -
#undef: Hebt die Definition eines Symbols auf.
Mit #define wird ein Symbol definiert. Wenn Sie das Symbol als Ausdruck verwenden, der an die #if-Anweisung übergeben wird, wird der Ausdruck als true ausgewertet, wie in folgendem Beispiel dargestellt:
#define VERBOSE
#if VERBOSE
Console.WriteLine("Verbose output version");
#endif
Hinweis
In C# sollten primitive Konstanten mit dem Schlüsselwort const definiert werden. Eine const-Deklaration erstellt ein static-Member, das zur Laufzeit nicht geändert werden kann. Die #define-Direktive kann nicht zur Deklaration konstanter Werte wie in C und C++ verwendet werden. Wenn Sie über mehrere solcher Konstanten verfügen, erwägen Sie, eine separate "Constants"-Klasse zu erstellen.
Symbole können verwendet werden, um Bedingungen für die Kompilierung anzugeben. Ein Symbol kann entweder mit #if oder mit #elif überprüft werden. Für die bedingte Kompilierung kann auch ConditionalAttribute verwendet werden. Ein Symbol kann zwar definiert werden, aber es kann ihm kein Wert zugewiesen werden. Die #define-Direktive muss in einer Datei vor allen Anweisungen, bei denen es sich nicht um Präprozessordirektiven handelt, verwendet werden. Sie können ein Symbol auch mit der Compileroption DefineConstants definieren. Die Definition eines Symbols kann mit #undef aufgehoben werden.
Definieren von Bereichen
Sie können Codebereiche definieren, die mithilfe der beiden folgenden Präprozessoranweisungen in einer Gliederung reduziert werden können:
-
#region: Beginnt einen Bereich. -
#endregion: Beendet einen Bereich.
Mit #region können Sie einen Codeblock festlegen, der bei Verwendung der Gliederungsfunktion des Code-Editors erweitert oder reduziert werden kann. Es ist bei längeren Codedateien praktischer, einen oder mehrere Bereiche zu reduzieren oder auszublenden, sodass Sie sich auf den Teil der Datei konzentrieren können, an dem Sie gerade arbeiten. Das folgende Beispiel veranschaulicht, wie Sie einen Bereich definieren:
#region MyClass definition
public class MyClass
{
static void Main()
{
}
}
#endregion
Ein #region-Block muss mit einer #endregion-Anweisung beendet werden. Ein #region-Block kann sich nicht mit einem #if-Block überschneiden. Allerdings kann ein #region-Block in einen #if-Block und ein #if-Block in einen #region-Block geschachtelt werden.
Fehler- und Warnungsinformationen
Mit den folgenden Anweisungen weisen Sie den Compiler an, benutzerdefinierte Compilerfehler und -warnungen zu generieren und Zeileninformationen zu steuern:
-
#error: Generiert einen Compilerfehler mit einer angegebenen Meldung. -
#warning: Generiert eine Compilerwarnung mit einer angegebenen Meldung. -
#line: Ändert die Zeilennummer, die mit Compilermeldungen gedruckt wird.
Mit #error können Sie von einem bestimmten Ort in Ihrem Code aus eine benutzerdefinierte Fehlermeldung CS1029 generieren. Zum Beispiel:
#error Deprecated code in this method.
Hinweis
Der Compiler behandelt #error version auf besondere Weise und meldet den Compilerfehler CS8304 mit einer Nachricht, die die verwendeten Compiler- und Sprachversionen enthält.
Mit #warning können Sie von einem bestimmten Ort in Ihrem Code aus eine Compilerwarnung CS1030 der Stufe 1 generieren. Zum Beispiel:
#warning Deprecated code in this method.
Mit #line können Sie die Zeilennummer des Compilers und (optional) die Dateinamensausgabe für Fehler und Warnungen bearbeiten.
Das folgende Beispiel zeigt, wie Sie zwei Warnungen melden können, die Zeilennummern zugeordnet sind. Die #line 200-Direktive erzwingt es, die Nummer der nächsten Zeile auf 200 festzulegen (obwohl der Standardwert #6 ist); und bis zur nächsten #line-Direktive wird der Dateiname als "Special" ausgegeben. Die #line default-Direktive stellt die Zeilennummerierung auf die Standardnummerierung zurück, wodurch die umnummerierten Zeilen durch die vorherige Direktive gezählt werden.
class MainClass
{
static void Main()
{
#line 200 "Special"
int i;
int j;
#line default
char c;
float f;
#line hidden // numbering not affected
string s;
double d;
}
}
Bei der Kompilierung wird die folgende Ausgabe erzeugt:
Special(200,13): warning CS0168: The variable 'i' is declared but never used
Special(201,13): warning CS0168: The variable 'j' is declared but never used
MainClass.cs(9,14): warning CS0168: The variable 'c' is declared but never used
MainClass.cs(10,15): warning CS0168: The variable 'f' is declared but never used
MainClass.cs(12,16): warning CS0168: The variable 's' is declared but never used
MainClass.cs(13,16): warning CS0168: The variable 'd' is declared but never used
Die #line-Anweisung könnte in einem automatischen Zwischenschritt im Buildprozess verwendet werden. Wenn beispielsweise Zeilen aus der ursprünglichen Quellcodedatei entfernt würden, Sie jedoch trotzdem möchten, dass der Compiler eine Ausgabe basierend auf der ursprünglichen Zeilennummerierung in der Datei generiert, könnten Sie Zeilen entfernen und anschließend die ursprüngliche Zeilennummerierung mit #line simulieren.
Die #line hidden-Anweisung blendet die aufeinanderfolgenden Zeilen im Debugger aus, sodass alle Zeilen zwischen einer #line hidden-Anweisung und der nächsten #line-Anweisung (vorausgesetzt, es handelt sich nicht um eine weitere #line hidden-Anweisung) übersprungen werden, wenn der Entwickler den Code durchläuft. Diese Option kann auch dazu verwendet werden, ASP.NET die Möglichkeit zu geben, zwischen benutzerdefiniertem und computergeneriertem Code zu unterscheiden. Obwohl ASP.NET der primäre Verbraucher dieses Features ist, ist es wahrscheinlich, dass mehr Quellgeneratoren es nutzen.
Eine #line hidden-Anweisung hat keine Auswirkung auf Dateinamen oder Zeilennummern bei der Fehlerberichterstattung. Wenn der Compiler einen Fehler in einem ausgeblendeten Block findet, meldet der Compiler den aktuellen Dateinamen und die Zeilennummer des Fehlers.
Die #line filename-Anweisung gibt den Dateinamen an, von dem Sie möchten, dass er in der Compilerausgabe erscheint. Standardmäßig wird der tatsächliche Name der Quellcodedatei verwendet. Der Dateiname muss sich in doppelten Anführungszeichen ("") befinden und einer Zeilennummer folgen.
Sie können eine neue Form der Direktive #line verwenden:
#line (1, 1) - (5, 60) 10 "partial-class.cs"
/*34567*/int b = 0;
Die Komponenten dieser Variante werden im Folgenden erläutert:
-
(1, 1): Dies ist die Startzeile und -spalte für das erste Zeichen in der Zeile, die auf die Anweisung folgt. In diesem Beispiel wird die nächste Zeile als Zeile 1, Spalte 1 gemeldet. -
(5, 60): Dies ist die Endzeile und -spalte für den markierten Bereich. -
10: Dies ist der Spaltenversatz, der benötigt wird, damit die#line-Anweisung wirksam wird. In diesem Beispiel wird die 10. Spalte als Spalte 1 gemeldet. Die Deklarationint b = 0;beginnt an dieser Spalte. Dieses Feld ist optional. Wenn es nicht angegeben wird, wird die Anweisung in der ersten Spalte wirksam. -
"partial-class.cs": Dies ist der Name der Ausgabedatei.
Im vorherigen Beispiel wird die folgende Warnung generiert:
partial-class.cs(1,5,1,6): warning CS0219: The variable 'b' is assigned but its value is never used
Nach der Neuzuordnung befindet sich die Variable b in der ersten Zeile der Datei partial-class.cs bei Zeichen 6.
Domänenspezifische Sprachen (DSLs) verwenden dieses Format in der Regel, um eine bessere Zuordnung von der Quelldatei zur generierten C#-Ausgabe zu ermöglichen. Die häufigste Verwendung dieser erweiterten #line Direktive besteht darin, Warnungen oder Fehler, die in einer generierten Datei angezeigt werden, der ursprünglichen Quelle neu zuzuordnen. Betrachten Sie beispielsweise diese Razor-Seite:
@page "/"
Time: @DateTime.NowAndThen
Der Eigenschaft DateTime.Now wurde fälschlicherweise der Typ DateTime.NowAndThen zugewiesen. Der generierte C#-Code für diesen Razor-Codeschnipsel sieht in page.g.cs wie folgt aus:
_builder.Add("Time: ");
#line (2, 6) - (2, 27) 15 "page.razor"
_builder.Add(DateTime.NowAndThen);
Die Compilerausgabe für den vorherigen Codeschnipsel lautet:
page.razor(2, 2, 2, 27)error CS0117: 'DateTime' does not contain a definition for 'NowAndThen'
Zeile 2, Spalte 6 in page.razor ist der Ort, an dem der Text @DateTime.NowAndThen beginnt, der von (2, 6) in der Richtlinie angegeben wird. Diese Spanne von @DateTime.NowAndThen endet bei Zeile 2, Spalte 27, wie in der Direktive durch (2, 27) angegeben. Der Text für DateTime.NowAndThen beginnt in Spalte 15 von page.g.cs, vermerkt durch die 15 in der Richtlinie. Der Compiler meldet den Fehler an der entsprechenden Stelle in page.razor. Der Entwickler kann direkt zum Fehler im Quellcode navigieren, anstatt in der generierten Quelle.
Weitere Beispiele für dieses Format finden Sie im Abschnitt Featurespezifikation zu den Beispielen.
Pragmas
#pragma gibt dem Compiler spezielle Anweisungen für die Kompilierung der Datei, in der es auftritt. Der Compiler muss die verwendeten Pragmen unterstützen. Das heißt, Sie können mit #pragma keine benutzerdefinierten Präprozessoranweisungen erstellen.
-
#pragma warning: Aktiviert oder deaktiviert Warnungen. -
#pragma checksum: Generiert eine Prüfsumme.
#pragma pragma-name pragma-arguments
Dabei stellt pragma-name den Namen eines erkannten Pragmas und pragma-arguments die pragmaspezifischen Argumente dar.
#pragma Warnung
#pragma warning kann bestimmte Warnungen aktivieren oder deaktivieren. Die #pragma warning disable format und #pragma warning enable format steuern, wie Codeblöcke von Visual Studio formatiert werden.
#pragma warning disable warning-list
#pragma warning restore warning-list
Dabei ist warning-list eine durch Trennzeichen getrennte Liste von Warnnummern, z. B. 414, CS3021. Das Präfix „CS“ ist optional. Wenn keine Warnzahlen angegeben werden, deaktiviert disable alle Warnungen und restore aktiviert sie.
Hinweis
Um Warnzahlen in Visual Studio zu suchen, erstellen Sie Ihr Projekt und suchen Sie nach den Warnzahlen im Fenster Ausgabe.
disable wirkt sich ab der nächsten Zeile der Quelldatei aus. Die Warnung wird in der Zeile nach restore wiederhergestellt. Enthält die Datei kein restore, werden die Warnungen in der ersten Zeile aller späteren Dateien derselben Kompilierung im Standardzustand wiederhergestellt.
// pragma_warning.cs
using System;
#pragma warning disable 414, CS3021
[CLSCompliant(false)]
public class C
{
int i = 1;
static void Main()
{
}
}
#pragma warning restore CS3021
[CLSCompliant(false)] // CS3021
public class D
{
int i = 1;
public static void F()
{
}
}
Eine andere Form des warning pragma deaktiviert oder stellt Visual Studio-Formatierungsbefehle in Codeblöcken wieder her:
#pragma warning disable format
#pragma warning restore format
Visual Studio-Formatbefehle ändern keinen Text in Codeblöcken, in denen disable format wirksam ist. Formatbefehle, z. B. STRG+K, STRG+D-, ändern diese Codebereiche nicht. Mit diesem Pragma können Sie die visuelle Darstellung Ihres Codes genau steuern.
#pragma-Prüfsumme
Erstellt für Quelldateien Prüfsummen, um beim Debuggen von ASP.NET-Seiten zu helfen.
#pragma checksum "filename" "{guid}" "checksum bytes"
Dabei ist "filename" der Name der Datei, die auf Änderungen oder Updates überwacht werden soll, "{guid}" die GUID (Global Unique Identifier) für den Hashalgorithmus und "checksum_bytes" die Zeichenfolge von Hexadezimalziffern, die die Bytes der Prüfsumme darstellen. Dabei muss es sich um eine gerade Anzahl hexadezimaler Ziffern handeln. Eine ungerade Anzahl von Ziffern führt zu einer Warnung zur Kompilierzeit, und die Anweisung wird ignoriert.
Der Visual Studio-Debugger verwendet eine Prüfsumme, um sicherzustellen, dass immer die richtige Quelle gefunden wird. Der Compiler berechnet die Prüfsumme für eine Quelldatei, und speichert das Ergebnis in der Program Database-Datei (PDB). Der Debugger verwendet anschließend die PDB-Datei, um sie mit der Prüfsumme zu vergleichen, die für die Quelldatei berechnet wird.
Diese Lösung funktioniert nicht bei ASP.NET-Projekten, weil die berechnete Prüfsumme für die generierte Quelldatei und nicht für die ASPX-Datei gilt.
#pragma checksum stellt für ASP.NET-Seiten Unterstützung von Prüfsummen bereit, um dieses Problem zu beheben.
Wenn Sie ein ASP.NET-Projekt in Visual C# erstellen, enthält die generierte Quelldatei eine Prüfsumme für die ASPX-Datei, von der die Quelle generiert wird. Der Compiler schreibt anschließend diese Informationen in die PDB-Datei.
Findet der Compiler keine #pragma checksum-Anweisung in der Datei, berechnet er die Prüfsumme und schreibt den Wert in die PDB-Datei.
class TestClass
{
static int Main()
{
#pragma checksum "file.cs" "{406EA660-64CF-4C82-B6F0-42D48172A799}" "ab007f1d23d9" // New checksum
}
}