Bagikan melalui


Pembuatan sumber untuk pemanggilan platform

.NET 7 memperkenalkan generator sumber untuk P/Invokes yang mengenali LibraryImportAttribute dalam kode C#.

Saat tidak menggunakan pembuatan sumber, sistem interop bawaan dalam runtime .NET menghasilkan stub IL—aliran instruksi IL yang JIT-ed—pada waktu proses untuk memfasilitasi transisi dari dikelola ke tidak terkelola. Kode berikut menunjukkan pendefinisian lalu memanggil P/Invoke yang menggunakan mekanisme ini:

[DllImport(
    "nativelib",
    EntryPoint = "to_lower",
    CharSet = CharSet.Unicode)]
internal static extern string ToLower(string str);

// string lower = ToLower("StringToConvert");

Stub IL menangani marshalling parameter dan mengembalikan nilai dan memanggil kode yang tidak dikelola sambil menghormati pengaturan pada DllImportAttribute yang memengaruhi bagaimana kode yang tidak dikelola harus dipanggil (misalnya, SetLastError). Karena stub IL ini dihasilkan pada waktu proses, itu tidak tersedia untuk kompilator ahead-of-time (AOT) atau skenario pemangkasan IL. Generasi IL mewakili biaya penting untuk dipertimbangkan untuk marshalling. Biaya ini dapat diukur dalam hal performa aplikasi dan dukungan untuk platform target potensial yang mungkin tidak mengizinkan pembuatan kode dinamis. Model aplikasi AOT Asli mengatasi masalah dengan pembuatan kode dinamis dengan melakukan prakompilasi semua kode sebelumnya langsung ke kode asli. Penggunaan DllImport bukanlah opsi untuk platform yang memerlukan skenario AOT Asli penuh dan oleh karena itu menggunakan pendekatan lain (misalnya, pembuatan sumber) lebih tepat. Men-debug logika marshalling dalam DllImport skenario juga merupakan latihan non-sepele.

Generator sumber P/Invoke, yang disertakan dengan .NET 7 SDK dan diaktifkan secara default, mencari LibraryImportAttribute static metode dan partial untuk memicu pembuatan sumber waktu kompilasi kode marshalling, menghapus kebutuhan untuk pembuatan stub IL pada waktu proses dan memungkinkan P/Invoke untuk diinlin. Penganalisis dan perbaikan kode juga disertakan untuk membantu migrasi dari sistem bawaan ke generator sumber dan dengan penggunaan secara umum.

Penggunaan dasar

dirancang LibraryImportAttribute agar mirip dengan DllImportAttribute penggunaan. Kita dapat mengonversi contoh sebelumnya untuk menggunakan pembuatan sumber P/Invoke dengan menggunakan LibraryImportAttribute dan menandai metode sebagai partial alih-alih extern:

[LibraryImport(
    "nativelib",
    EntryPoint = "to_lower",
    StringMarshalling = StringMarshalling.Utf16)]
internal static partial string ToLower(string str);

Selama kompilasi, generator sumber akan memicu untuk menghasilkan implementasi ToLower metode yang menangani marshalling string parameter dan mengembalikan nilai sebagai UTF-16. Karena marshalling sekarang menghasilkan kode sumber, Anda benar-benar dapat melihat dan menelusuri logika dalam debugger.

MarshalAs

Generator sumber juga menghormati MarshalAsAttribute. Kode sebelumnya juga dapat ditulis sebagai:

[LibraryImport(
    "nativelib",
    EntryPoint = "to_lower")]
[return: MarshalAs(UnmanagedType.LPWStr)]
internal static partial string ToLower(
    [MarshalAs(UnmanagedType.LPWStr)] string str);

Beberapa pengaturan untuk MarshalAsAttribute tidak didukung. Generator sumber akan memancarkan kesalahan jika Anda mencoba menggunakan pengaturan yang tidak didukung. Untuk informasi selengkapnya, lihat Perbedaan dari DllImport.

Konvensi panggilan

Untuk menentukan konvensi panggilan, gunakan UnmanagedCallConvAttribute, misalnya:

[LibraryImport(
    "nativelib",
    EntryPoint = "to_lower",
    StringMarshalling = StringMarshalling.Utf16)]
[UnmanagedCallConv(
    CallConvs = new[] { typeof(CallConvStdcall) })]
internal static partial string ToLower(string str);

Perbedaan dari DllImport

LibraryImportAttribute dimaksudkan untuk menjadi konversi langsung dari DllImportAttribute dalam banyak kasus, tetapi ada beberapa perubahan yang disengaja:

  • CallingConvention tidak setara pada LibraryImportAttribute. UnmanagedCallConvAttribute harus digunakan sebagai gantinya.
  • CharSet (untuk CharSet) telah diganti dengan StringMarshalling (untuk StringMarshalling). ANSI telah dihapus dan UTF-8 sekarang tersedia sebagai opsi kelas satu.
  • BestFitMapping dan ThrowOnUnmappableChar tidak memiliki setara. Bidang-bidang ini hanya relevan saat melakukan marsekal untai (karakter) ANSI di Windows. Kode yang dihasilkan untuk marshalling string ANSI akan memiliki perilaku yang setara dan BestFitMapping=false ThrowOnUnmappableChar=false.
  • ExactSpelling tidak setara. Bidang ini adalah pengaturan windows-sentris dan tidak berpengaruh pada sistem operasi non-Windows. Nama metode atau EntryPoint harus ejaan yang tepat dari nama titik entri. Bidang ini memiliki penggunaan historis yang terkait dengan akhiran A dan W yang digunakan dalam pemrograman Win32.
  • PreserveSig tidak setara. Bidang ini adalah pengaturan windows-sentris. Kode yang dihasilkan selalu langsung menerjemahkan tanda tangan.
  • Proyek harus ditandai tidak aman menggunakan AllowUnsafeBlocks.

Ada juga perbedaan dalam dukungan untuk beberapa pengaturan pada MarshalAsAttribute, marsekal default jenis tertentu, dan atribut terkait interop lainnya. Untuk informasi selengkapnya, lihat dokumentasi kami tentang perbedaan kompatibilitas.

Lihat juga