Brongeneratie voor platform-aanroepen
.NET 7 introduceert een brongenerator voor P/Invokes die de LibraryImportAttribute in C#-code herkent.
Wanneer het geen brongeneratie gebruikt, genereert het ingebouwde interoperabiliteitssysteem in de .NET-runtime een IL-stub, een stroom IL-instructies die JIT-ed is, tijdens runtime om de overgang van beheerd naar onbeheerd te vergemakkelijken. De volgende code toont het definiƫren en aanroepen van een P/Invoke die gebruikmaakt van dit mechanisme:
[DllImport(
"nativelib",
EntryPoint = "to_lower",
CharSet = CharSet.Unicode)]
internal static extern string ToLower(string str);
// string lower = ToLower("StringToConvert");
De IL-stub verwerkt het marshallen van parameters en retourwaarden en het aanroepen van de onbeheerde code terwijl de instellingen worden DllImportAttribute gerespecteerd die van invloed zijn op de manier waarop de onbeheerde code moet worden aangeroepen (bijvoorbeeld SetLastError). Omdat deze IL-stub tijdens runtime wordt gegenereerd, is deze niet beschikbaar voor AOT-compilers (ahead-of-time) of IL-trimmingscenario's. De generatie van de IL vertegenwoordigt een belangrijke kosten om rekening mee te houden voor marshalling. Deze kosten kunnen worden gemeten in termen van toepassingsprestaties en ondersteuning voor potentiƫle doelplatforms die mogelijk geen dynamische code genereren toestaan. Het systeemeigen AOT-toepassingsmodel lost problemen op met het genereren van dynamische code door alle code vooraf rechtstreeks in systeemeigen code te compileren. Het gebruik DllImport
is geen optie voor platforms waarvoor volledige systeemeigen AOT-scenario's zijn vereist en daarom is het gebruik van andere benaderingen (bijvoorbeeld het genereren van bronnen) geschikter. Het opsporen van fouten in de marshalllogica in DllImport
scenario's is ook een niet-triviale oefening.
De P/Invoke-brongenerator, die is opgenomen in de .NET 7 SDK en standaard ingeschakeld, zoekt naar LibraryImportAttribute een static
en partial
methode om het genereren van marshallcode voor compileertijd te activeren, waardoor de noodzaak voor het genereren van een IL-stub tijdens runtime wordt verwijderd en de P/Invoke inline kan worden geplaatst. Analysefuncties en codefixers zijn ook opgenomen om u te helpen bij de migratie van het ingebouwde systeem naar de brongenerator en met gebruik in het algemeen.
Basaal gebruik
Het LibraryImportAttribute is ontworpen om vergelijkbaar te zijn met DllImportAttribute in gebruik. We kunnen het vorige voorbeeld converteren om P/Invoke-brongeneratie te gebruiken met behulp van de LibraryImportAttribute methode en de methode te markeren als partial
in plaats van extern
:
[LibraryImport(
"nativelib",
EntryPoint = "to_lower",
StringMarshalling = StringMarshalling.Utf16)]
internal static partial string ToLower(string str);
Tijdens de compilatie wordt de brongenerator geactiveerd om een implementatie te genereren van de ToLower
methode die marshalling van de string
parameter afhandelt en de waarde retourneert als UTF-16. Omdat de marshalling nu broncode wordt gegenereerd, kunt u de logica in een foutopsporingsprogramma bekijken en doorlopen.
MarshalAs
De brongenerator respecteert ook de MarshalAsAttribute. De voorgaande code kan ook worden geschreven als:
[LibraryImport(
"nativelib",
EntryPoint = "to_lower")]
[return: MarshalAs(UnmanagedType.LPWStr)]
internal static partial string ToLower(
[MarshalAs(UnmanagedType.LPWStr)] string str);
Sommige instellingen voor MarshalAsAttribute worden niet ondersteund. De brongenerator verzendt een fout als u niet-ondersteunde instellingen probeert te gebruiken. Zie Verschillen van DllImport voor meer informatie.
Oproepconventie
Als u de oproepconventie wilt opgeven, gebruikt UnmanagedCallConvAttributeu bijvoorbeeld:
[LibraryImport(
"nativelib",
EntryPoint = "to_lower",
StringMarshalling = StringMarshalling.Utf16)]
[UnmanagedCallConv(
CallConvs = new[] { typeof(CallConvStdcall) })]
internal static partial string ToLower(string str);
Verschillen van DllImport
LibraryImportAttribute is bedoeld als een eenvoudige conversie van DllImportAttribute in de meeste gevallen, maar er zijn enkele opzettelijke wijzigingen:
- CallingConvention heeft geen equivalent op LibraryImportAttribute. UnmanagedCallConvAttribute moet in plaats daarvan worden gebruikt.
- CharSet (voor CharSet) is vervangen door StringMarshalling (voor StringMarshalling). ANSI is verwijderd en UTF-8 is nu beschikbaar als eersteklas optie.
- BestFitMapping en ThrowOnUnmappableChar geen equivalent hebben. Deze velden waren alleen relevant bij het marshallen van een ANSI-tekenreeks in Windows. De gegenereerde code voor het marshallen van een ANSI-tekenreeks heeft het equivalente gedrag van
BestFitMapping=false
enThrowOnUnmappableChar=false
. - ExactSpelling heeft geen equivalent. Dit veld was een Windows-gerichte instelling en had geen effect op niet-Windows-besturingssystemen. De naam van de methode of EntryPoint moet de exacte spelling van de naam van het invoerpunt zijn. Dit veld heeft historische toepassingen die betrekking hebben op de
A
enW
achtervoegsels die worden gebruikt in Win32-programmering. - PreserveSig heeft geen equivalent. Dit veld was een Windows-gerichte instelling. De gegenereerde code vertaalt de handtekening altijd rechtstreeks.
- Het project moet zijn gemarkeerd als onveilig met AllowUnsafeBlocks.
Er zijn ook verschillen in ondersteuning voor sommige instellingen op MarshalAsAttribute, standaard marshalling van bepaalde typen en andere interop-gerelateerde kenmerken. Zie onze documentatie over compatibiliteitsverschillen voor meer informatie.