C#-Präprozessoranweisungen
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.
Nullable-Kontext
Die Präprozessoranweisung #nullable
legt den Nullable-Anmerkungskontext und den Nullable-Warnungskontext fest. Die Anweisung steuert, ob Nullable-Anmerkungen wirksam sind und ob Warnungen zur NULL-Zulässigkeit angegeben werden. Jeder Kontext 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 Warnungskontexte und hat Vorrang vor anderen Einstellungen auf Projektebene. Eine Anweisung legt die von ihr gesteuerten Kontexte fest, bis sie von einer anderen Anweisung überschrieben wird oder bis zum Ende der Quelldatei.
Die Auswirkungen der Anweisungen lauten wie folgt:
#nullable disable
: Diese Anweisung legt die Nullable-Anmerkungskontexte und -Warnungskontexte auf deaktiviert fest.#nullable enable
: Diese Anweisung legt die Nullable-Anmerkungskontexte und -Warnungskontexte auf aktiviert fest.#nullable restore
: Diese Anweisung stellt die Nullable-Anmerkungskontexte und -Warnungskontexte der Projekteinstellungen wieder her.#nullable disable annotations
: Diese Anweisung legt den Nullable-Anmerkungskontext auf deaktiviert fest.#nullable enable annotations
: Diese Anweisung legt den Nullable-Anmerkungskontext auf aktiviert fest.#nullable restore annotations
: Diese Anweisung stellt den Nullable-Anmerkungskontext der Projekteinstellungen wieder her.#nullable disable warnings
: Diese Anweisung legt den Nullable-Warnungskontext auf deaktiviert fest.#nullable enable warnings
: Diese Anweisung legt den Nullable-Warnungskontext auf aktiviert fest.#nullable restore warnings
: Diese Anweisung stellt den Nullable-Warnungskontext der 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.
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 ein boolescher Wert und überprüft nur, ob das Symbol definiert wurde. Beispielsweise wird der folgende Code kompiliert, wenn DEBUG
definiert ist:
#if DEBUG
Console.WriteLine("Debug version");
#endif
Der folgende Code wird kompiliert, wenn MYTEST
nicht 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 !
(nicht) verwenden, um auszuwerten, ob mehrere Symbole definiert wurden. Symbole und Operatoren können auch mit Klammern gruppiert werden.
Im Folgenden finden Sie eine komplexe Anweisung, mit der der Code neuere .NET-Features nutzen und dennoch abwärtskompatibel bleiben kann. 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.
Eine bedingte Anweisung, die mit einer #if
-Anweisung beginnt, muss explizit mit einer #endif
-Anweisung beendet werden. Über #define
können Sie ein Symbol definieren. Wird dieses Symbol als Ausdruck an die #if
-Anweisung übergeben, wird der Ausdruck als true
ausgewertet. Sie können ein Symbol auch mit der Compileroption DefineConstants definieren. Die Definition eines Symbols kann mit #undef
aufgehoben werden. Der Gültigkeitsbereich eines mit #define
erstellten Symbols ist die Datei, in der es definiert wurde. Zwischen einem Symbol, das mit DefineConstants oder mit #define
definiert wird, und einer Variablen mit dem gleichen Namen kommt es zu keinem Konflikt. Das bedeutet, dass ein Variablenname nicht an eine Präprozessoranweisung übergeben werden sollte und ein Symbol nur von einer Präprozessoranweisung ausgewertet werden kann.
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. 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.
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 | Symbole | 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 , NET47 , NET462 , NET461 , NET46 , NET452 , NET451 , NET45 , NET40 , NET35 , NET20 |
NET48_OR_GREATER , NET472_OR_GREATER , NET471_OR_GREATER , NET47_OR_GREATER , NET462_OR_GREATER , NET461_OR_GREATER , NET46_OR_GREATER , NET452_OR_GREATER , NET451_OR_GREATER , NET45_OR_GREATER , NET40_OR_GREATER , NET35_OR_GREATER , NET20_OR_GREATER |
|
.NET Standard | NETSTANDARD , NETSTANDARD2_1 , NETSTANDARD2_0 , NETSTANDARD1_6 , NETSTANDARD1_5 , NETSTANDARD1_4 , NETSTANDARD1_3 , NETSTANDARD1_2 , NETSTANDARD1_1 , NETSTANDARD1_0 |
NETSTANDARD2_1_OR_GREATER , NETSTANDARD2_0_OR_GREATER , NETSTANDARD1_6_OR_GREATER , NETSTANDARD1_5_OR_GREATER , NETSTANDARD1_4_OR_GREATER , NETSTANDARD1_3_OR_GREATER , NETSTANDARD1_2_OR_GREATER , NETSTANDARD1_1_OR_GREATER , NETSTANDARD1_0_OR_GREATER |
|
.NET 5 oder höher (und .NET Core) | NET , NET9_0 , NET8_0 , NET7_0 , NET6_0 , NET5_0 , NETCOREAPP , NETCOREAPP3_1 , NETCOREAPP3_0 , NETCOREAPP2_2 , NETCOREAPP2_1 , NETCOREAPP2_0 , NETCOREAPP1_1 , NETCOREAPP1_0 |
NET8_0_OR_GREATER , NET7_0_OR_GREATER , NET6_0_OR_GREATER , NET5_0_OR_GREATER , NETCOREAPP3_1_OR_GREATER , NETCOREAPP3_0_OR_GREATER , NETCOREAPP2_2_OR_GREATER , NETCOREAPP2_1_OR_GREATER , NETCOREAPP2_0_OR_GREATER , NETCOREAPP1_1_OR_GREATER , NETCOREAPP1_0_OR_GREATER |
ANDROID , BROWSER , IOS , MACCATALYST , MACOS , TVOS , WINDOWS ,[OS][version] (z. B. IOS15_1 ),[OS][version]_OR_GREATER (z. B. 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_GREATER
undNET10_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.
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# müssen primitive Konstanten mithilfe des Schlüsselworts const
definiert werden. Eine const
-Deklaration erstellt einen static
-Member, der zur Laufzeit nicht geändert werden kann. Die #define
-Direktive kann nicht wie in C und C++ zur Deklaration konstanter Werte 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. 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. 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
-Anweisung erzwingt die Nummer 200 der nächsten Zeile (obwohl der Standardwert #6 ist), und bis zur nächsten #line
-Anweisung wird der Dateiname als „Special“ gemeldet. Die #line default
-Standardanweisung legt die Zeilennummerierung auf deren Standardnummerierung fest, bei der die Zeilen gezählt werden, die von der vorherigen Anweisung neu nummeriert wurden.
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 Anwender dieser Funktion ist, werden sich wahrscheinlich mehr Quellgeneratoren diese zunutze machen.
Eine #line hidden
-Anweisung hat keine Auswirkung auf Dateinamen oder Zeilennummern bei der Fehlerberichterstattung. Das bedeutet, wenn der Compiler in einem ausgeblendeten Block einen Fehler findet, meldet er 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 in doppelten Anführungszeichen ("") und hinter einer Zeilennummer stehen.
Ab C# 10 können Sie eine neue Form der #line
-Direktive 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. An diesem Ort beginnt die Deklarationint b = 0;
. 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
-Anweisung besteht darin, Warnungen oder Fehler, die in einer generierten Datei angezeigt werden, wieder der ursprünglichen Quelle 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'
In Zeile 2, Spalte 6 in page.razor
beginnt der Text @DateTime.NowAndThen
. Dies wird durch (2, 6)
in der Anweisung angegeben. Dieser Bereich von @DateTime.NowAndThen
endet in Zeile 2, Spalte 27. Dies wird durch (2, 27)
in der Anweisung angegeben. Der Text für DateTime.NowAndThen
beginnt in Spalte 15 von page.g.cs
. Dies wird durch 15
in der Anweisung angegeben. Wenn alle Argumente zusammengefügt werden, meldet der Compiler den Fehler an seiner Position 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. Die Anweisungen müssen vom Compiler unterstützt werden. 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 warning
#pragma warning
kann bestimmte Warnungen aktivieren oder deaktivieren.
#pragma warning disable warning-list
#pragma warning restore warning-list
Dabei ist warning-list
eine durch Trennzeichen getrennte Liste mit Warnungsnummern. 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()
{
}
}
#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
}
}