Share via


C#-preprocessorrichtlijnen

Hoewel de compiler geen afzonderlijke preprocessor heeft, worden de instructies die in deze sectie worden beschreven, verwerkt alsof er een is. U gebruikt ze om u te helpen bij voorwaardelijke compilatie. In tegenstelling tot C- en C++-instructies kunt u deze instructies niet gebruiken om macro's te maken. Een preprocessorrichtlijn moet de enige instructie op een regel zijn.

Null-context

Met #nullable de preprocessorrichtlijn wordt de context van de null-aantekening en de context voor null-waarschuwingen ingesteld. Deze richtlijn bepaalt of null-aantekeningen effect hebben en of waarschuwingen voor null-baarheid worden gegeven. Elke context is uitgeschakeld of ingeschakeld.

Beide contexten kunnen worden opgegeven op projectniveau (buiten C#-broncode) waarbij het Nullable element wordt toegevoegd aan het PropertyGroup element. De #nullable richtlijn bepaalt de contexten van aantekeningen en waarschuwingen en heeft voorrang op de instellingen op projectniveau. Met een richtlijn worden de context(en) ingesteld die deze beheert totdat een andere instructie deze overschrijft of tot het einde van het bronbestand.

Het effect van de richtlijnen is als volgt:

  • #nullable disable: Hiermee stelt u de aantekening en waarschuwingscontexten in die null kunnen worden uitgeschakeld.
  • #nullable enable: Hiermee stelt u de aantekenings- en waarschuwingscontexten in op null die moeten worden ingeschakeld.
  • #nullable restore: herstelt de null-aantekening en waarschuwingscontexten naar projectinstellingen.
  • #nullable disable annotations: Hiermee stelt u de context van de null-aantekening in op uitgeschakeld.
  • #nullable enable annotations: Hiermee stelt u de context voor null-aantekening in op ingeschakeld.
  • #nullable restore annotations: hiermee herstelt u de context van de null-aantekening in projectinstellingen.
  • #nullable disable warnings: Hiermee stelt u de context voor null-waarschuwingen in op uitgeschakeld.
  • #nullable enable warnings: Hiermee stelt u de context voor null-waarschuwingen in op ingeschakeld.
  • #nullable restore warnings: hiermee herstelt u de context voor null-waarschuwingen naar projectinstellingen.

Voorwaardelijke compilatie

U gebruikt vier preprocessorrichtlijnen voor het beheren van voorwaardelijke compilatie:

  • #if: Hiermee opent u een voorwaardelijke compilatie, waarbij code alleen wordt gecompileerd als het opgegeven symbool is gedefinieerd.
  • #elif: Sluit de voorgaande voorwaardelijke compilatie en opent een nieuwe voorwaardelijke compilatie op basis van of het opgegeven symbool is gedefinieerd.
  • #else: Hiermee sluit u de voorgaande voorwaardelijke compilatie en opent u een nieuwe voorwaardelijke compilatie als het vorige opgegeven symbool niet is gedefinieerd.
  • #endif: Hiermee sluit u de voorgaande voorwaardelijke compilatie.

De C#-compiler compileert de code tussen de #if instructie en #endif de instructie alleen als het opgegeven symbool is gedefinieerd of niet is gedefinieerd wanneer de ! operator niet wordt gebruikt. In tegenstelling tot C en C++ kan een numerieke waarde aan een symbool niet worden toegewezen. De #if instructie in C# is Booleaanse waarde en test alleen of het symbool al dan niet is gedefinieerd. De volgende code wordt bijvoorbeeld gecompileerd wanneer DEBUG deze is gedefinieerd:

#if DEBUG
    Console.WriteLine("Debug version");
#endif

De volgende code wordt gecompileerd wanneer MYTEST deze niet is gedefinieerd:

#if !MYTEST
    Console.WriteLine("MYTEST is not defined");
#endif

U kunt de operators == (gelijkheid) en!= (ongelijkheid) gebruiken om te testen op de bool waarden true of false. true betekent dat het symbool is gedefinieerd. De instructie #if DEBUG heeft dezelfde betekenis als #if (DEBUG == true). U kunt de && operators (en), || (of) en ! (niet) gebruiken om te evalueren of er meerdere symbolen zijn gedefinieerd. U kunt ook symbolen en operatoren met haakjes groeperen.

Hier volgt een complexe instructie waarmee uw code kan profiteren van nieuwere .NET-functies terwijl deze compatibel blijft met eerdere versies. Stel dat u een NuGet-pakket in uw code gebruikt, maar dat het pakket alleen .NET 6 en hoger ondersteunt, evenals .NET Standard 2.0 en hoger:

#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

#if, samen met de #else#elif#endif, , en #define#undef instructies, kunt u code opnemen of uitsluiten op basis van het bestaan van een of meer symbolen. Voorwaardelijke compilatie kan handig zijn bij het compileren van code voor een foutopsporingsbuild of bij het compileren van een specifieke configuratie.

Een voorwaardelijke richtlijn die begint met een #if richtlijn moet expliciet worden beëindigd met een #endif richtlijn. #define hiermee kunt u een symbool definiëren. Door het symbool te gebruiken als de expressie die aan de #if instructie wordt doorgegeven, wordt de expressie geëvalueerd.true U kunt ook een symbool definiëren met de compileroptie DefineConstants. U kunt een symbool ongedaan maken met #undef. Het bereik van een symbool dat is gemaakt met #define is het bestand waarin het is gedefinieerd. Een symbool dat u definieert met DefineConstants of met een #define variabele van dezelfde naam, conflicteren niet. Een variabelenaam mag dus niet worden doorgegeven aan een preprocessorrichtlijn en een symbool kan alleen worden geëvalueerd door een preprocessorrichtlijn.

#elif hiermee kunt u een samengestelde voorwaardelijke instructie maken. De #elif expressie wordt geëvalueerd als noch de voorgaande #if , optionele, #elif instructieexpressies worden geëvalueerd true. Als een #elif expressie wordt geëvalueerd true, evalueert de compiler alle code tussen de #elif en de volgende voorwaardelijke instructie. Voorbeeld:

#define VC7
//...
#if DEBUG
    Console.WriteLine("Debug build");
#elif VC7
    Console.WriteLine("Visual Studio 7");
#endif

#else hiermee kunt u een samengestelde voorwaardelijke instructie maken, zodat, als geen van de expressies in de voorgaande #if of (optionele) #elif instructies wordt geëvalueerd true, de compiler alle code tussen #else en de volgende #endifevalueert. #endif(#endif) moet de volgende preprocessorrichtlijn na #elsezijn.

#endif geeft het einde van een voorwaardelijke richtlijn, die begon met de #if richtlijn.

Het buildsysteem is ook op de hoogte van vooraf gedefinieerde preprocessorsymbolen die verschillende doelframeworks in SDK-projecten vertegenwoordigen . Ze zijn handig bij het maken van toepassingen die zich kunnen richten op meer dan één .NET-versie.

Doelframeworks Symbolen Aanvullende symbolen
(beschikbaar in .NET 5+ SDK's)
Platformsymbolen (alleen beschikbaar)
wanneer u een besturingssysteemspecifieke TFM opgeeft)
.NET Framework NETFRAMEWORK, , NET472NET48, NET471, , NET47, , NET462NET461, NET46, NET451NET452NET45NET40NET35,NET20 NET48_OR_GREATER, , NET472_OR_GREATER, , , , NET461_OR_GREATER, NET46_OR_GREATER, NET452_OR_GREATER, NET45_OR_GREATERNET40_OR_GREATERNET35_OR_GREATERNET451_OR_GREATERNET462_OR_GREATERNET47_OR_GREATERNET471_OR_GREATERNET20_OR_GREATER
.NET Standard NETSTANDARD, , NETSTANDARD2_0, NETSTANDARD1_6NETSTANDARD2_1, , NETSTANDARD1_5, NETSTANDARD1_4, , NETSTANDARD1_1NETSTANDARD1_2NETSTANDARD1_3NETSTANDARD1_0 NETSTANDARD2_1_OR_GREATER, , NETSTANDARD1_6_OR_GREATERNETSTANDARD2_0_OR_GREATER, NETSTANDARD1_5_OR_GREATER, , NETSTANDARD1_4_OR_GREATER, NETSTANDARD1_3_OR_GREATER, NETSTANDARD1_1_OR_GREATERNETSTANDARD1_2_OR_GREATERNETSTANDARD1_0_OR_GREATER
.NET 5+ (en .NET Core) NET, , NET8_0, , , , NETCOREAPP, NETCOREAPP3_1, NETCOREAPP3_0, NETCOREAPP2_1NETCOREAPP2_0NETCOREAPP1_1NETCOREAPP2_2NET5_0NET6_0NET7_0NETCOREAPP1_0 NET8_0_OR_GREATER, , NET7_0_OR_GREATERNET6_0_OR_GREATER, NET5_0_OR_GREATER, NETCOREAPP3_1_OR_GREATER, , NETCOREAPP3_0_OR_GREATER, , NETCOREAPP2_0_OR_GREATERNETCOREAPP2_1_OR_GREATERNETCOREAPP1_1_OR_GREATERNETCOREAPP2_2_OR_GREATERNETCOREAPP1_0_OR_GREATER ANDROID, , BROWSERIOS, MACCATALYST, , MACOS, , TVOSWINDOWS
[OS][version] (bijvoorbeeld IOS15_1),
[OS][version]_OR_GREATER (bijvoorbeeld IOS15_1_OR_GREATER)

Notitie

  • Versieloze symbolen worden gedefinieerd, ongeacht de versie die u wilt gebruiken.
  • Versiespecifieke symbolen worden alleen gedefinieerd voor de versie waarop u zich richt.
  • De <framework>_OR_GREATER symbolen worden gedefinieerd voor de versie waarop u zich richt en alle eerdere versies. Als u zich bijvoorbeeld richt op .NET Framework 2.0, worden de volgende symbolen gedefinieerd: NET20, NET20_OR_GREATER, NET11_OR_GREATERen NET10_OR_GREATER.
  • De NETSTANDARD<x>_<y>_OR_GREATER symbolen worden alleen gedefinieerd voor .NET Standard-doelen en niet voor doelen die .NET Standard implementeren, zoals .NET Core en .NET Framework.
  • Deze verschillen van de doelframework monikers (TFM's) die worden gebruikt door de eigenschap MSBuild TargetFramework en NuGet.

Notitie

Voor traditionele, niet-SDK-projecten moet u de symbolen voor voorwaardelijke compilatie handmatig configureren voor de verschillende doelframeworks in Visual Studio via de eigenschappenpagina's van het project.

Andere vooraf gedefinieerde symbolen zijn de DEBUG en TRACE constanten. U kunt de waarden die zijn ingesteld voor het project overschrijven met behulp van #define. Het DEBUG-symbool wordt bijvoorbeeld automatisch ingesteld, afhankelijk van uw buildconfiguratie-eigenschappen ('Foutopsporing' of 'Release').

In het volgende voorbeeld ziet u hoe u een MYTEST symbool voor een bestand definieert en vervolgens de waarden van de MYTEST en DEBUG symbolen test. De uitvoer van dit voorbeeld is afhankelijk van of u het project hebt gebouwd op de foutopsporings - of releaseconfiguratiemodus .

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

In het volgende voorbeeld ziet u hoe u kunt testen op verschillende doelframeworks, zodat u indien mogelijk nieuwere API's kunt gebruiken:

public class MyClass
{
    static void Main()
    {
#if NET40
        WebClient _client = new WebClient();
#else
        HttpClient _client = new HttpClient();
#endif
    }
    //...
}

Symbolen definiëren

U gebruikt de volgende twee preprocessorrichtlijnen om symbolen voor voorwaardelijke compilatie te definiëren of ongedaan te maken:

  • #define: Definieer een symbool.
  • #undef: Een symbool ongedaan maken.

U gebruikt #define om een symbool te definiëren. Wanneer u het symbool gebruikt als de expressie die aan de #if instructie wordt doorgegeven, wordt de expressie geëvalueerd true, zoals in het volgende voorbeeld wordt weergegeven:

#define VERBOSE

#if VERBOSE
   Console.WriteLine("Verbose output version");
#endif

Notitie

In C# moeten primitieve constanten worden gedefinieerd met behulp van het const trefwoord. Een const declaratie maakt een static lid dat tijdens runtime niet kan worden gewijzigd. De #define instructie kan niet worden gebruikt om constante waarden te declareren, zoals meestal wordt gedaan in C en C++. Als u verschillende dergelijke constanten hebt, kunt u overwegen om een afzonderlijke klasse Constanten te maken om deze vast te houden.

Symbolen kunnen worden gebruikt om voorwaarden voor compilatie op te geven. U kunt testen op het symbool met of #if #elif. U kunt ook de ConditionalAttribute functie gebruiken om voorwaardelijke compilatie uit te voeren. U kunt een symbool definiëren, maar u kunt geen waarde toewijzen aan een symbool. De #define instructie moet worden weergegeven in het bestand voordat u instructies gebruikt die niet ook preprocessorrichtlijnen zijn. U kunt ook een symbool definiëren met de compileroptie DefineConstants. U kunt een symbool ongedaan maken met #undef.

Regio's definiëren

U kunt regio's met code definiëren die in een overzicht kunnen worden samengevouwen met behulp van de volgende twee preprocessorrichtlijnen:

  • #region: Een regio starten.
  • #endregion: Een regio beëindigen.

#region hiermee kunt u een codeblok opgeven dat u kunt uitvouwen of samenvouwen wanneer u de overzichtsfunctie van de code-editor gebruikt. In langere codebestanden is het handig om een of meer regio's samen te vouwen of te verbergen, zodat u zich kunt richten op het deel van het bestand waaraan u momenteel werkt. In het volgende voorbeeld ziet u hoe u een regio definieert:

#region MyClass definition
public class MyClass
{
    static void Main()
    {
    }
}
#endregion

Een #region blok moet worden beëindigd met een #endregion richtlijn. Een #region blok kan niet overlappen met een #if blok. Een #region blok kan echter worden genest in een #if blok en een #if blok kan worden genest in een #region blok.

Fout- en waarschuwingsgegevens

U geeft de compiler opdracht om door de gebruiker gedefinieerde compilerfouten en waarschuwingen te genereren, en regelinformatie te beheren met behulp van de volgende instructies:

  • #error: Genereer een compilerfout met een opgegeven bericht.
  • #warning: Genereer een compilerwaarschuwing met een specifiek bericht.
  • #line: Wijzig het regelnummer dat wordt afgedrukt met compilerberichten.

#error hiermee kunt u een door de gebruiker gedefinieerde CS1029-fout genereren op basis van een specifieke locatie in uw code. Bijvoorbeeld:

#error Deprecated code in this method.

Notitie

De compiler behandelt op een speciale manier en rapporteert #error version een compilerfout, CS8304, met een bericht met de gebruikte compiler- en taalversies.

#warning hiermee kunt u een waarschuwing van één compiler op CS1030 niveau één genereren vanaf een specifieke locatie in uw code. Voorbeeld:

#warning Deprecated code in this method.

#line hiermee kunt u de regelnummering van de compiler wijzigen en (optioneel) de bestandsnaamuitvoer wijzigen voor fouten en waarschuwingen.

In het volgende voorbeeld ziet u hoe u twee waarschuwingen rapporteert die zijn gekoppeld aan regelnummers. De #line 200 richtlijn dwingt af dat het nummer van de volgende regel 200 is (hoewel de standaardwaarde #6 is), en tot de volgende #line instructie wordt de bestandsnaam gerapporteerd als 'Speciaal'. De #line default richtlijn retourneert de regelnummering tot de standaardnummering, waarmee de regels worden geteld die opnieuw zijn genummerd door de vorige richtlijn.

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

Compilatie produceert de volgende uitvoer:

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

De #line richtlijn kan worden gebruikt in een geautomatiseerde, tussenliggende stap in het bouwproces. Als bijvoorbeeld regels uit het oorspronkelijke broncodebestand zijn verwijderd, maar u toch de compiler uitvoer wilde laten genereren op basis van de oorspronkelijke regelnummering in het bestand, kunt u regels verwijderen en vervolgens de oorspronkelijke regelnummering simuleren met #line.

De #line hidden richtlijn verbergt de opeenvolgende regels van het foutopsporingsprogramma, zodat wanneer de ontwikkelaar de code doorloopt, alle regels tussen een #line hidden en de volgende #line richtlijn (ervan uitgaande dat het geen andere #line hidden richtlijn is) worden overgestapt. Deze optie kan ook worden gebruikt om ASP.NET onderscheid te maken tussen door de gebruiker gedefinieerde en door de machine gegenereerde code. Hoewel ASP.NET de primaire consument van deze functie is, is het waarschijnlijk dat meer brongeneratoren er gebruik van maken.

Een #line hidden richtlijn heeft geen invloed op bestandsnamen of regelnummers in foutrapportage. Als de compiler een fout in een verborgen blok vindt, rapporteert de compiler de huidige bestandsnaam en het regelnummer van de fout.

De #line filename instructie geeft de bestandsnaam op die u wilt weergeven in de compileruitvoer. Standaard wordt de werkelijke naam van het broncodebestand gebruikt. De bestandsnaam moet tussen dubbele aanhalingstekens ("") staan en moet worden voorafgegaan door een regelnummer.

Vanaf C# 10 kunt u een nieuwe vorm van de #line instructie gebruiken:

#line (1, 1) - (5, 60) 10 "partial-class.cs"
/*34567*/int b = 0;

De onderdelen van dit formulier zijn:

  • (1, 1): De beginregel en kolom voor het eerste teken op de regel die volgt op de richtlijn. In dit voorbeeld wordt de volgende regel gerapporteerd als regel 1, kolom 1.
  • (5, 60): De eindlijn en kolom voor het gemarkeerde gebied.
  • 10: de kolomverrekening voor de #line richtlijn van kracht. In dit voorbeeld wordt de 10e kolom gerapporteerd als kolom één. Daar begint de verklaring int b = 0; . Dit veld is optioneel. Als u dit weglaat, wordt de richtlijn van kracht op de eerste kolom.
  • "partial-class.cs": De naam van het uitvoerbestand.

In het voorgaande voorbeeld wordt de volgende waarschuwing gegenereerd:

partial-class.cs(1,5,1,6): warning CS0219: The variable 'b' is assigned but its value is never used

Na het opnieuw toewijzen bevindt de variabele zich bop de eerste regel, op teken zes, van het bestand partial-class.cs.

Domeinspecifieke talen (DSLs) gebruiken deze indeling doorgaans om een betere toewijzing te bieden van het bronbestand naar de gegenereerde C#-uitvoer. Het meest voorkomende gebruik van deze uitgebreide #line richtlijn is om waarschuwingen of fouten die in een gegenereerd bestand worden weergegeven, opnieuw toe te wijzen aan de oorspronkelijke bron. Denk bijvoorbeeld aan deze scheermespagina:

@page "/"
Time: @DateTime.NowAndThen

De eigenschap DateTime.Now is onjuist getypt als DateTime.NowAndThen. De gegenereerde C# voor dit razor-fragment ziet er als volgt uit:page.g.cs

  _builder.Add("Time: ");
#line (2, 6) - (2, 27) 15 "page.razor"
  _builder.Add(DateTime.NowAndThen);

De compileruitvoer voor het voorgaande codefragment is:

page.razor(2, 2, 2, 27)error CS0117: 'DateTime' does not contain a definition for 'NowAndThen'

Regel 2, kolom 6 waarin page.razor de tekst @DateTime.NowAndThen begint. Dat staat (2, 6) in de richtlijn. Die reeks @DateTime.NowAndThen uiteinden op regel 2, kolom 27. Dat wordt opgemerkt door de (2, 27) richtlijn. De tekst voor DateTime.NowAndThen begint in kolom 15 van page.g.cs. Dat wordt opgemerkt door de 15 richtlijn. Alle argumenten samenvoegen en de compiler rapporteert de fout op de locatie in page.razor. De ontwikkelaar kan rechtstreeks naar de fout in de broncode navigeren, niet naar de gegenereerde bron.

Zie de functiespecificatie in de sectie over voorbeelden voor meer voorbeelden voor meer voorbeelden van deze indeling.

Pragmas

#pragma geeft de compiler speciale instructies voor de compilatie van het bestand waarin het wordt weergegeven. De instructies moeten worden ondersteund door de compiler. Met andere woorden, u kunt geen aangepaste voorverwerkingsinstructies maken #pragma .

#pragma pragma-name pragma-arguments

Waar pragma-name is de naam van een herkende pragma en pragma-arguments de pragma-specifieke argumenten.

waarschuwing voor #pragma

#pragma warning kan bepaalde waarschuwingen in- of uitschakelen.

#pragma warning disable warning-list
#pragma warning restore warning-list

Waar warning-list is een door komma's gescheiden lijst met waarschuwingsnummers. Het voorvoegsel CS is optioneel. Als er geen waarschuwingsnummers zijn opgegeven, disable worden alle waarschuwingen uitgeschakeld en restore worden alle waarschuwingen ingeschakeld.

Notitie

Als u waarschuwingsnummers in Visual Studio wilt vinden, bouwt u uw project en zoekt u vervolgens naar de waarschuwingsnummers in het venster Uitvoer .

De disable actie wordt van kracht vanaf de volgende regel van het bronbestand. De waarschuwing wordt hersteld op de regel na de restore. Als het bestand niet restore aanwezig is, worden de waarschuwingen teruggezet naar de standaardstatus op de eerste regel van latere bestanden in dezelfde compilatie.

// 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()
    {
    }
}

controlesom #pragma

Hiermee worden controlesommen gegenereerd voor bronbestanden om te helpen met foutopsporing ASP.NET pagina's.

#pragma checksum "filename" "{guid}" "checksum bytes"

Waar "filename" is de naam van het bestand dat controle op wijzigingen of updates vereist, "{guid}" is de GUID (Globally Unique Identifier) voor het hash-algoritme en "checksum_bytes" is de tekenreeks van hexadecimale cijfers die de bytes van de controlesom vertegenwoordigen. Moet een even aantal hexadecimale cijfers zijn. Een oneven aantal cijfers resulteert in een waarschuwing over de compilatietijd en de instructie wordt genegeerd.

Het foutopsporingsprogramma van Visual Studio maakt gebruik van een controlesom om ervoor te zorgen dat er altijd de juiste bron wordt gevonden. De compiler berekent de controlesom voor een bronbestand en verzendt vervolgens de uitvoer naar het PDB-bestand (program database). Het foutopsporingsprogramma gebruikt vervolgens de PDB om te vergelijken met de controlesom die wordt berekend voor het bronbestand.

Deze oplossing werkt niet voor ASP.NET projecten, omdat de berekende controlesom voor het gegenereerde bronbestand is in plaats van het .aspx bestand. Om dit probleem op te lossen, #pragma checksum biedt controlesomondersteuning voor ASP.NET pagina's.

Wanneer u een ASP.NET project maakt in Visual C#, bevat het gegenereerde bronbestand een controlesom voor het .aspx-bestand waaruit de bron wordt gegenereerd. De compiler schrijft deze informatie vervolgens naar het PDB-bestand.

Als de compiler geen instructie in het bestand vindt #pragma checksum , wordt de controlesom berekend en wordt de waarde naar het PDB-bestand geschreven.

class TestClass
{
    static int Main()
    {
        #pragma checksum "file.cs" "{406EA660-64CF-4C82-B6F0-42D48172A799}" "ab007f1d23d9" // New checksum
    }
}