Generování zdrojového kódu pro vyvolání platformy
.NET 7 zavádí generátor zdrojů pro volání nespravovaného LibraryImportAttribute kódu v jazyce C#.
Pokud nepoužívá generování zdroje, integrovaný systém vzájemné spolupráce v modulu runtime .NET generuje zástupný kód IL – datový proud instrukcí IL, který je za běhu – a usnadňuje tak přechod ze spravovaného na nespravované. Následující kód ukazuje definování a následné volání nespravovaného kódu, který používá tento mechanismus:
[DllImport(
"nativelib",
EntryPoint = "to_lower",
CharSet = CharSet.Unicode)]
internal static extern string ToLower(string str);
// string lower = ToLower("StringToConvert");
Zástupný kód IL zpracovává zařazování parametrů a návratové hodnoty a volá nespravovaný kód při zachování nastavení DllImportAttribute , která ovlivňují způsob vyvolání nespravovaného kódu (například SetLastError). Vzhledem k tomu, že se tento zástupný kód IL generuje za běhu, není k dispozici pro scénáře oříznutí předem (AOT) ani pro ořezávání IL. Generování IL představuje důležité náklady, které je třeba zvážit při zařazování. Tyto náklady je možné měřit z hlediska výkonu aplikace a podpory potenciálních cílových platforem, které neumožňují dynamické generování kódu. Nativní aplikační model AOT řeší problémy s dynamickým generováním kódu předkompilováním veškerého kódu předem přímo do nativního kódu. Použití DllImport
není možnost pro platformy, které vyžadují úplné nativní scénáře AOT, a proto je vhodnější použít jiné přístupy (například generování zdroje). Ladění logiky zařazování ve DllImport
scénářích je také netiktivní cvičení.
Generátor zdrojového kódu P/Invoke, který je součástí sady .NET 7 SDK a povolený ve výchozím nastavení, hledá LibraryImportAttribute static
a partial
metodu pro aktivaci generování kódu pro kompilaci a zařazování kódu, což odstraňuje potřebu generování zástupných procedur IL za běhu a umožňuje inlinovat volání nespravovaného kódu. Analyzátory a opravy kódu jsou také zahrnuty, aby pomohly s migrací z integrovaného systému do generátoru zdrojů a obecně s využitím.
Základní použití
Tato LibraryImportAttribute funkce je navržená tak, aby byla podobná DllImportAttribute použití. Předchozí příklad můžeme převést na použití generování zdroje P/Invoke pomocí LibraryImportAttribute metody a označení metody jakopartial
:extern
[LibraryImport(
"nativelib",
EntryPoint = "to_lower",
StringMarshalling = StringMarshalling.Utf16)]
internal static partial string ToLower(string str);
Během kompilace se spustí generátor zdroje, který vygeneruje implementaci ToLower
metody, která zpracovává zařazování parametru string
a návratovou hodnotu jako UTF-16. Vzhledem k tomu, že se teď vygeneruje zdrojový kód, můžete se na logiku v ladicím programu podívat a projít si ji.
MarshalAs
Zdroj generátoru také MarshalAsAttributerespektuje . Předchozí kód lze také napsat takto:
[LibraryImport(
"nativelib",
EntryPoint = "to_lower")]
[return: MarshalAs(UnmanagedType.LPWStr)]
internal static partial string ToLower(
[MarshalAs(UnmanagedType.LPWStr)] string str);
Některá nastavení MarshalAsAttribute nejsou podporovaná. Pokud se pokusíte použít nepodporovaná nastavení, generátor zdroje vygeneruje chybu. Další informace naleznete v tématu Rozdíly z knihovny DllImport.
Konvenci
Pokud chcete zadat konvenci volání, použijte UnmanagedCallConvAttributenapříklad:
[LibraryImport(
"nativelib",
EntryPoint = "to_lower",
StringMarshalling = StringMarshalling.Utf16)]
[UnmanagedCallConv(
CallConvs = new[] { typeof(CallConvStdcall) })]
internal static partial string ToLower(string str);
Rozdíly od DllImport
LibraryImportAttribute má být ve většině případů jednoduchým převodem DllImportAttribute , ale existují některé záměrné změny:
- CallingConvention nemá žádný ekvivalent dne LibraryImportAttribute. UnmanagedCallConvAttribute místo toho by se měla použít.
- CharSet (pro CharSet) byla nahrazena písmenem StringMarshalling (pro StringMarshalling). ANSI byl odebrán a UTF-8 je nyní k dispozici jako prvotřídní možnost.
- BestFitMapping a ThrowOnUnmappableChar nemají žádný ekvivalent. Tato pole byla relevantní pouze při zařazování řetězce ANSI ve Windows. Vygenerovaný kód pro zařazování řetězce ANSI bude mít ekvivalentní chování
BestFitMapping=false
aThrowOnUnmappableChar=false
. - ExactSpelling nemá žádný ekvivalent. Toto pole bylo nastavení zaměřené na Windows a nemělo žádný vliv na operační systémy jiné než Windows. Název metody nebo EntryPoint by měl být přesným pravopisem názvu vstupního bodu. Toto pole má historické použití související s
A
příponami aW
příponami používanými v programování win32. - PreserveSig nemá žádný ekvivalent. Toto pole bylo nastavení zaměřené na Windows. Vygenerovaný kód vždy přímo přeloží podpis.
- Projekt musí být označený jako nebezpečný pomocí AllowUnsafeBlocks.
Existují také rozdíly v podpoře některých nastavení MarshalAsAttribute, výchozí zařazování určitých typů a dalších atributů souvisejících s interoperabilitou. Další informace najdete v naší dokumentaci k rozdílům v kompatibilitě.