LibraryImport ve Kaynak Tarafından Oluşturulan P/Invoke
DllImport'tan daha iyi performans sunan, AOT uyumlu ve kaynak tarafından oluşturulan sıralama için [LibraryImport] (C# 11+) kullanın.
LibraryImport ve Kaynak Tarafından Oluşturulan P/Invoke, CoddyKit'te ücretsiz bir C# Academy dersidir. Bu, 4 dersinin 2. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, C# Academy öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. C# Academy kursu toplamda 4 dersten oluşur.
LibraryImport Neden Kullanılmalı?
[LibraryImport], .NET 7'de (C# 11) kaynak kodu üreten ve AOT ile uyumlu bir [DllImport] alternatifi olarak kullanıma sunuldu. Klasik DllImport, çalışma zamanında yansıma aracılığıyla veri dönüştürmeye dayanır ve bu durum Native AOT için sorunludur. LibraryImport, tüm veri dönüştürme kodunu derleme zamanında üretir.
LibraryImport Yöntemi Bildirme
static partial yöntemini [LibraryImport] ile işaretleyin. Kaynak kodu oluşturucu uygulamayı tamamlar. İçeren sınıfı da partial olarak işaretlemeniz gerekir.
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);
}LibraryImport'ta Dize Veri Dönüştürme
DllImport'un aksine LibraryImport, dize veri dönüştürmesini açıkça belirtmenizi gerektirir. StringMarshalling numaralandırmasını veya MarshalAs özniteliklerini kullanabilirsiniz; böylece veri dönüştürme maliyeti görünür ve denetlenebilir olur.
// 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);Yapıların Veri Dönüştürülmesi
Yapılar için, yönetilen türün yerel gösterime nasıl eşlendiğini tanımlamak üzere [NativeMarshalling] ekleyin. Kaynak kodu oluşturucu, güvenli ve bellek ayırma işlemlerini en aza indiren kod üretmek için dönüştürücü türünü kullanır.
[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; }
}DllImport ile LibraryImport Karşılaştırması
DllImport, çalışma zamanında yorumlanır; başlangıç yavaştır, yansıma tabanlıdır ve AOT kırpmasıyla uyumsuzdur. LibraryImport, derleme zamanında iyileştirilmiş C# kodu üretir: çalışma zamanında yansıma kullanılmaz, kırpmayla uyumludur ve kıyaslama testlerinde ölçülebilir biçimde daha hızlıdır.
// 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 bodySetLastError ve Hata İşleme
İşletim sistemi hata kodunu yakalamak için [LibraryImport] içinde SetLastError = true ayarlayın. Çağrıdan sonra hata kodunu almak için Marshal.GetLastPInvokeError() (tercih edilen yöntem) veya Marshal.GetLastWin32Error() kullanın.
[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> ve Bellek Veri Dönüştürme
Kaynak kodu üretilen P/Invoke'un avantajlarından biri, Span<T> için birinci sınıf destektir. Bir ReadOnlySpan<byte> geçirmek, dizilerle DllImport kullanıldığında gerekli olacak sabitleme ve bellek ayırma işlemlerini önler.
[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);Kaynak Kodu Oluşturmayı Etkinleştirme
.NET 7 veya sonraki bir sürümü hedefleyen bir projede System.Runtime.InteropServices ad alanına başvurduğunuzda kaynak kodu oluşturma otomatik olarak etkinleştirilir. Daha eski hedefler için Microsoft.Interop.SourceGeneration çözümleyici paketine ihtiyacınız vardır.
<!-- 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>Oluşturulan Kodu İnceleme
Oluşturulan dosyaların obj/ klasörüne yazılması için csproj dosyanıza <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> ekleyin. Böylece kaynak kodu oluşturucunun tam olarak ne ürettiğini inceleyebilirsiniz; bu, öğrenmek için harika bir çalışmadır.
// 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);
}Gerçek Dünya: Bir C Kitaplığını Sarmalama
Yaygın bir yaklaşım, tüm LibraryImport bildirimlerini içeren statik bir sarmalayıcı sınıf tanımlamak ve bunun üzerinde üst düzey, güvenli bir API sunmaktır. partial bildirimlerini internal/private tutun ve yalnızca güvenli wrappers'ı herkese açık olarak sunun.
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;
}Hızlı Kontrol
[LibraryImport]'un [DllImport]'a göre temel avantajı nedir?
Özet: LibraryImport ve Kaynak Kodu Üreten P/Invoke
Önemli çıkarımlar:
[LibraryImport], AOT için güvenli P/Invoke kullanımında[DllImport]'un yerini alır- Veri dönüştürme derleme zamanında oluşturulur; çalışma zamanında yansıma kullanılmaz
static partialyöntem vepartialsınıf gerektirir- Dize veri dönüştürmesi
StringMarshallingveyaMarshalAsaracılığıyla açıkça belirtilmelidir - Sabitleme yükü olmadan birinci sınıf
Span<T>desteği sunar - Oluşturulan kodu
EmitCompilerGeneratedFilesile inceleyebilirsiniz
Sıkça Sorulan Sorular
“LibraryImport ve Kaynak Tarafından Oluşturulan P/Invoke” dersi ücretsiz mi?
Evet — “LibraryImport ve Kaynak Tarafından Oluşturulan P/Invoke” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve C# Academy kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. C# Academy kursu toplamda 4 dersten oluşur.
“LibraryImport ve Kaynak Tarafından Oluşturulan P/Invoke” dersinde ne öğreneceğim?
DllImport'tan daha iyi performans sunan, AOT uyumlu ve kaynak tarafından oluşturulan sıralama için [LibraryImport] (C# 11+) kullanın. C# Academy ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.
C# Academy öğrenmeye başlamak için deneyim gerekli mi?
Önceden deneyim gerekmez. CoddyKit'te C# Academy, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 2. dersidir.
“LibraryImport ve Kaynak Tarafından Oluşturulan P/Invoke” dersi ne kadar sürer?
Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.
Bu C# Academy dersinde kod yazıp çalıştırabilir miyim?
Evet. Her C# Academy dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.
Bu kursun tüm dersleri
- P/Invoke Temelleri
- LibraryImport ve Kaynak Tarafından Oluşturulan P/Invoke
- Güvenli Olmayan Kod, İşaretçiler ve Sabit Tamponlar
- COM Birlikte Çalışabilirliği ve Çalışma Zamanı Çağrılabilir Sarmalayıcıları