اندازهی قلم متن
تخمین مدت زمان مطالعهی مطلب:
دو دقیقه
دات نت 7 به همراه یک source generator جدید به نام LibraryImport است که کار جایگزینی DllImport قدیمی را انجام میدهد. برای مثال تا پیش از دات نت 7 برای فراخوانی یک متد native موجود در یک DLL نوشته شدهی به زبانهای ++C/C، به صورت زیر عمل میشد:
کاری که در اینجا در پشت صحنه انجام میشود، نوشتن کدهای IL مرتبطی، توسط NET runtime. است تا تبادل اطلاعات بین دو محیط متفاوت managed و unmanaged را میسر کند. چون این کدها در زمان اجرا تولید میشوند، در اختیار امکانات AOT کامپایلر (ahead-of-time) نیستند و به همین جهت برای مثال سناریوهای IL trimming و کاهش حجم، در مورد آنها اعمال نمیشود. همچنین باید درنظر داشت که سکوهای کاری هم هستند که امکان تولید کدهای پویا را در زمان اجرای برنامه ندارند. در یک چنین حالتهایی، استفاده از روشهایی مانند تولید کد خودکار توسط کامپایلر، ارجحیت بیشتری دارد. همچنین باید درنظر داشت که امکان دیباگ کدهای پشت صحنهی DllImport هم وجود ندارد.
معرفی LibraryImportAttribute در دات نت 7
تولید کنندهی کد مخصوص P/Invoke در دات نت 7، به دنبال ویژگی جدید LibraryImportAttribute بر روی متدهای استاتیک و partial میگردد تا کدهای متناظر با آنها را تولید کند. به این ترتیب نیاز به تولید اینگونه کدها در زمان اجرای برنامه مرتفع میشود و همچنین میتوان این کدها را در IDE خود بررسی و حتی دیباگ کرد.
همانطور که مشاهده میکنید، کارکرد این ویژگی بسیار شبیه به DllImportAttribute است که برای استفادهی از آن، متد قبلی، از حالت extern، به static partial تبدیل شدهاست.
امکان تبدیل خودکار کدهای قدیمی مبتنی بر DllImportAttribute به نمونههای جدید
برای تبدیل خودکار کدهای قدیمی موجود، فقط کافی است یک سطر زیر را به فایل editorconfig. پروژهی خود اضافه کنید:
پس از آن یک code fix و analyzer خودکار و توکار ظاهر شده و امکان تبدیل خودکار کدهای DllImport دار قدیمی را به نمونههای جدید LibraryImport دار، میدهد.
تغییرات صورت گرفته نسبت به DllImport قدیمی
نحوهی تعریف LibraryImportAttribute در اکثر موارد با DllImportAttribute تطابق دارد، منهای موارد زیر:
- در اینجا معادلی برای CallingConvention وجود ندارد. برای اینکار از UnmanagedCallConvAttribute استفاده میشود.
- CharSet با StringMarshalling تعویض شدهاست. ANSI حذف شدهاست و UTF-8 حالت پیشفرض است. برای مثال:
[DllImport( "nativelib", EntryPoint = "to_lower", CharSet = CharSet.Unicode)] internal static extern string ToLower(string str); // string lower = ToLower("StringToConvert");
تولید کنندهی کد مخصوص P/Invoke در دات نت 7، به دنبال ویژگی جدید LibraryImportAttribute بر روی متدهای استاتیک و partial میگردد تا کدهای متناظر با آنها را تولید کند. به این ترتیب نیاز به تولید اینگونه کدها در زمان اجرای برنامه مرتفع میشود و همچنین میتوان این کدها را در IDE خود بررسی و حتی دیباگ کرد.
[LibraryImport( "nativelib", EntryPoint = "to_lower", StringMarshalling = StringMarshalling.Utf16)] internal static partial string ToLower(string str);
امکان تبدیل خودکار کدهای قدیمی مبتنی بر DllImportAttribute به نمونههای جدید
برای تبدیل خودکار کدهای قدیمی موجود، فقط کافی است یک سطر زیر را به فایل editorconfig. پروژهی خود اضافه کنید:
dotnet_diagnostic.SYSLIB1054.severity = suggestion
تغییرات صورت گرفته نسبت به DllImport قدیمی
نحوهی تعریف LibraryImportAttribute در اکثر موارد با DllImportAttribute تطابق دارد، منهای موارد زیر:
- در اینجا معادلی برای CallingConvention وجود ندارد. برای اینکار از UnmanagedCallConvAttribute استفاده میشود.
- CharSet با StringMarshalling تعویض شدهاست. ANSI حذف شدهاست و UTF-8 حالت پیشفرض است. برای مثال:
// Before public static class Native { [DllImport(nameof(Native), CharSet = CharSet.Unicode)] public extern static string ToLower(string str); } // After public static partial class Native { [LibraryImport(nameof(Native), StringMarshalling = StringMarshalling.Utf16)] public static partial string ToLower(string str); }