0Pricing
C# Academy · Pelajaran

LibraryImport & P/Invoke yang Dibuat dari Sumber

Gunakan [LibraryImport] (C# 11+) untuk marshaling yang kompatibel dengan AOT dan dibuat dari sumber, dengan performa melampaui DllImport.

LibraryImport & P/Invoke yang Dibuat dari Sumber adalah pelajaran C# Academy gratis di CoddyKit. Ini adalah pelajaran 2 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar C# Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus C# Academy mencakup 4 pelajaran total.

Mengapa LibraryImport?

[LibraryImport] diperkenalkan di .NET 7 (C# 11) sebagai pengganti [DllImport] yang dibuat oleh generator sumber dan kompatibel dengan AOT. DllImport klasik mengandalkan pemetaan saat program berjalan melalui refleksi—hal ini bermasalah bagi Native AOT. LibraryImport menghasilkan seluruh kode pemetaan saat waktu kompilasi.

Mendeklarasikan Metode LibraryImport

Tandai metode static partial dengan [LibraryImport]. Generator sumber akan mengisi implementasinya. Anda juga harus menandai kelas yang memuatnya sebagai partial.

using System.Runtime.InteropServices;

internal static partial class NativeMethods
{
    // Source generator creates the P/Invoke body at compile time
    [LibraryImport("mylib", EntryPoint = "add_integers")]
    internal static partial int AddIntegers(int a, int b);

    // String marshaling must be explicit in LibraryImport
    [LibraryImport("mylib", StringMarshalling = StringMarshalling.Utf8)]
    internal static partial int ProcessString(string text);
}

Pemetaan String di LibraryImport

Berbeda dengan DllImport, LibraryImport mengharuskan Anda menentukan pemetaan string secara eksplisit. Anda dapat menggunakan enum StringMarshalling atau atribut MarshalAs, sehingga biaya pemetaan terlihat dan dapat dikendalikan.

// Option 1: StringMarshalling enum (all strings in method)
[LibraryImport("kernel32", StringMarshalling = StringMarshalling.Utf16)]
static partial bool CreateDirectory(string lpPathName, nint lpSecurityAttributes);

// Option 2: Per-parameter MarshalAs
[LibraryImport("libc")]
static partial int Open(
    [MarshalAs(UnmanagedType.LPUTF8Str)] string path,
    int flags);

// Option 3: MarshalUsing for custom marshalers
[LibraryImport("mylib")]
static partial void Process(
    [MarshalUsing(typeof(Utf8StringMarshaller))] string name);

Pemetaan Struktur

Untuk struktur, tambahkan [NativeMarshalling] guna menentukan cara tipe terkelola dipetakan ke representasi aslinya. Generator sumber menggunakan tipe pemeta untuk menghasilkan kode yang aman dan meminimalkan alokasi.

[NativeMarshalling(typeof(PointMarshaller))]
public struct Point
{
    public int X;
    public int Y;
}

[CustomMarshaller(typeof(Point), MarshalMode.Default, typeof(PointMarshaller))]
public static class PointMarshaller
{
    public static Point ConvertToManaged(NativePoint native)
        => new Point { X = native.X, Y = native.Y };
    public static NativePoint ConvertToUnmanaged(Point managed)
        => new NativePoint { X = managed.X, Y = managed.Y };

    [StructLayout(LayoutKind.Sequential)]
    public struct NativePoint { public int X, Y; }
}

Membandingkan DllImport dan LibraryImport

DllImport ditafsirkan saat program berjalan—awal yang lambat, berbasis refleksi, dan tidak kompatibel dengan pemangkasan AOT. LibraryImport menghasilkan kode C# yang dioptimalkan saat pembangunan: tanpa refleksi saat program berjalan, aman terhadap pemangkasan, dan terbukti lebih cepat dalam pengujian kinerja.

// Old — DllImport (still works, but avoid for new AOT code)
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
static extern bool MoveFile(string src, string dst);

// New — LibraryImport (AOT-safe, source-generated)
[LibraryImport("kernel32", StringMarshalling = StringMarshalling.Utf16,
                SetLastError = true)]
static partial bool MoveFile(string src, string dst);
// The compiler generates the actual P/Invoke wrapper body

SetLastError dan Penanganan Galat

Atur SetLastError = true dalam [LibraryImport] untuk menangkap kode galat sistem operasi. Gunakan Marshal.GetLastPInvokeError() (lebih disarankan) atau Marshal.GetLastWin32Error() untuk mengambilnya setelah pemanggilan.

[LibraryImport("kernel32", StringMarshalling = StringMarshalling.Utf16,
                SetLastError = true)]
static partial bool CreateDirectory(string path, nint secAttr);

bool ok = CreateDirectory(@"C:\Temp\NewDir", 0);
if (!ok)
{
    int err = Marshal.GetLastPInvokeError();
    // err is ERROR_ALREADY_EXISTS (183) if folder exists
    throw new Win32Exception(err);
}

Span<T> dan Pemetaan Memori

Salah satu keunggulan P/Invoke yang dibuat oleh generator sumber adalah dukungan penuh untuk Span<T>. Meneruskan ReadOnlySpan<byte> menghindari penyematan dan alokasi yang diperlukan oleh DllImport jika menggunakan larik.

[LibraryImport("mylib")]
static partial int ProcessBuffer(
    ReadOnlySpan<byte> data,
    int length);

// Usage — no fixed or GCHandle needed
byte[] buffer = Encoding.UTF8.GetBytes("hello");
int result = ProcessBuffer(buffer, buffer.Length);

// For output buffers use Span<byte>
[LibraryImport("mylib")]
static partial int FillBuffer(Span<byte> output, int maxLen);

Mengaktifkan Pembuatan Sumber

Pembuatan sumber diaktifkan secara otomatis saat Anda mereferensikan namespace System.Runtime.InteropServices dalam proyek yang menargetkan .NET 7+. Untuk target yang lebih lama, Anda memerlukan paket penganalisis Microsoft.Interop.SourceGeneration.

<!-- In your .csproj — no extra package needed on .NET 7+ -->
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <!-- Enable Roslyn analyzers and source generators -->
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <!-- AllowUnsafeBlocks may be needed for some marshalers -->
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
  </PropertyGroup>
</Project>

Memeriksa Kode yang Dihasilkan

Tambahkan <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> ke csproj untuk menulis berkas yang dihasilkan ke obj/. Dengan begitu, Anda dapat memeriksa secara tepat apa yang dihasilkan generator sumber—latihan belajar yang sangat baik.

// The generator emits something like this for a LibraryImport method:
// (simplified view of generated stub)

internal static partial int AddIntegers(int a, int b)
{
    // Direct call — no reflection, no boxing, fully inlineable
    return __PInvoke(a, b);

    [System.Runtime.InteropServices.DllImportAttribute(
        "mylib",
        EntryPoint = "add_integers",
        ExactSpelling = true)]
    static extern int __PInvoke(int a, int b);
}

Dunia Nyata: Membungkus Pustaka C

Pola yang umum adalah mendefinisikan kelas pembungkus statis dengan semua deklarasi LibraryImport, lalu menyediakan API aman tingkat tinggi di atasnya. Simpan deklarasi partial sebagai internal/private dan hanya tampilkan pembungkus aman tersebut secara publik.

internal static partial class LibSodiumNative
{
    private const string LibName = "libsodium";

    [LibraryImport(LibName, EntryPoint = "crypto_secretbox_keybytes")]
    internal static partial nuint KeyBytes();

    [LibraryImport(LibName, EntryPoint = "crypto_secretbox_easy")]
    internal static partial int SecretBoxEasy(
        Span<byte> ciphertext,
        ReadOnlySpan<byte> message,
        ulong mlen,
        ReadOnlySpan<byte> nonce,
        ReadOnlySpan<byte> key);
}

// Public safe wrapper hides the native signature
public static byte[] Encrypt(byte[] message, byte[] key, byte[] nonce)
{
    var cipher = new byte[message.Length + 16];
    LibSodiumNative.SecretBoxEasy(cipher, message, (ulong)message.Length, nonce, key);
    return cipher;
}

Pemeriksaan Singkat

Apa keuntungan utama [LibraryImport] dibandingkan [DllImport]?

Ringkasan: LibraryImport dan P/Invoke yang Dibuat oleh Generator Sumber

Poin-poin utama:

  • [LibraryImport] menggantikan [DllImport] untuk P/Invoke yang aman bagi AOT
  • Pemetaan dihasilkan saat waktu kompilasi—tanpa refleksi saat program berjalan
  • Memerlukan metode static partial dan kelas partial
  • Pemetaan string harus ditentukan secara eksplisit melalui StringMarshalling atau MarshalAs
  • Dukungan penuh untuk Span<T> tanpa biaya penyematan
  • Periksa kode yang dihasilkan dengan EmitCompilerGeneratedFiles

Pertanyaan yang Sering Diajukan

Apakah pelajaran “LibraryImport & P/Invoke yang Dibuat dari Sumber” gratis?

Ya — teks lengkap “LibraryImport & P/Invoke yang Dibuat dari Sumber” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus C# Academy, upgrade ke CoddyKit PRO. Kursus C# Academy mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “LibraryImport & P/Invoke yang Dibuat dari Sumber”?

Gunakan [LibraryImport] (C# 11+) untuk marshaling yang kompatibel dengan AOT dan dibuat dari sumber, dengan performa melampaui DllImport. Kamu berlatih C# Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai C# Academy?

Tidak diperlukan pengalaman sebelumnya. C# Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 4.

Berapa lama pelajaran “LibraryImport & P/Invoke yang Dibuat dari Sumber” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran C# Academy ini?

Ya. Setiap pelajaran C# Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Dasar-Dasar P/Invoke
  2. LibraryImport & P/Invoke yang Dibuat dari Sumber
  3. Kode Tidak Aman, Pointer & Buffer Tetap
  4. Interoperabilitas COM & Runtime Callable Wrapper
← Kembali ke C# Academy