لماذا لا يعيش C# في فراغ، وكيف يعمل ذلك
\n\nعندما بدأت العمل مع C# منذ حوالي عشر سنوات، كنت أعتقد أن .NET هو كون مكتفٍ ذاتيًا. المكتبات، الأطر، قواعد البيانات - كل شيء في متناول اليد. ولكن بعد ذلك جاءت مهمة: كنت بحاجة لاستخدام مكتبة C++ قديمة لمعالجة الإشارات. وهنا أدركت - تكامل C# مع اللغات الأخرى ليس ترفًا، بل ضرورة لأي مشروع جاد.
\n\nاليوم، C# هي لغة متعددة المنصات مع نظام بيئي غني، لكنها لا تستطيع فعل كل شيء. أحيانًا تحتاج لتشغيل سكريبت Python للتعلم الآلي، وأحيانًا لاستدعاء دالة أصلية من Rust لتحقيق أقصى أداء، وأحيانًا لتضمين محرك JavaScript لتوليد واجهة مستخدم ديناميكية. الخبر السار: C# يمكنه التعامل مع الجميع تقريبًا.
\n\nفي هذه المقالة، سأعرض سيناريوهات حقيقية لـ تفاعل C# مع اللغات الأخرى مع كود عملي، معايير أداء، والمزالق المحتملة. هيا بنا!
\n\nP/Invoke: الكلاسيكي لـ C وC++
\n\nPlatform Invocation Services (P/Invoke) هي آلية مدمجة في .NET لاستدعاء الدوال من مكتبات DLL الأصلية. ظهرت منذ الإصدار الأول من .NET ولا تزال أسرع طريقة للتكامل مع كود C/C++.
\n\nمثال أساسي: استدعاء دالة من C
\n\nلنفترض أن لدينا مكتبة أصلية math_helper.dll تحتوي على دالة:
// math_helper.h\nextern "C" __declspec(dllexport) double calculate_power(double base, int exp);\n\nفي C# نربطها كالتالي:
\n\nusing System.Runtime.InteropServices;\n\npublic class NativeMath\n{\n [DllImport("math_helper.dll", CallingConvention = CallingConvention.Cdecl)]\n public static extern double calculate_power(double base, int exp);\n}\n\n// الاستخدام\ndouble result = NativeMath.calculate_power(2.0, 10);\nConsole.WriteLine($"2^10 = {result}"); // 1024\n\nنقاط مهمة عند P/Invoke C#:
\n- \n
- حدد دائمًا
CallingConvention- غالبًاCdeclأوStdCall. \n - للسلاسل النصية استخدم
MarshalAs(UnmanagedType.LPStr)أوLPWStr. \n - مرر الهياكل بالمرجع عبر
refأوout. \n
P/Invoke يعطي تكاليف إضافية ضئيلة - حرفيًا بضع نانوثانية لكل استدعاء. إذا كنت بحاجة إلى دمج C# مع C++ للحسابات عالية التحميل - فهذا هو اختيارك.
\n\nC++/CLI: جسر بين العوالم
\n\nC++/CLI هو امتداد لـ Visual C++ يسمح بكتابة كود يعمل في كل من البيئة المُدارة (.NET) والبيئة غير المُدارة. إنها ليست لغة منفصلة، بل هجين يُستخدم غالبًا لإنشاء أغلفة لمكتبات C++.
\n\nمثال غلاف لـ OpenCV
\n\nلنفترض أن لدينا دالة C++ تعالج الصورة:
\n\n// NativeImageProcessor.h\n#pragma once\npublic ref class ImageProcessor\n{\npublic:\n static System::Drawing::Bitmap^ ApplyFilter(System::Drawing::Bitmap^ bmp);\n};\n\nداخليًا نستدعي OpenCV الأصلي، ونخرج Bitmap مُدارًا. من C# نستخدمها كمكتبة .NET عادية:
using ImageProcessorLib;\n\nvar img = new Bitmap("photo.jpg");\nvar processed = ImageProcessor.ApplyFilter(img);\nprocessed.Save("filtered.jpg");\n\nتكامل C++/CLI يعطي تحكمًا كاملاً في الذاكرة ويتجنب المارشالينغ. العيب - يصبح الكود معتمدًا على المنصة وأكثر تعقيدًا في التصحيح.
\n\nPython.NET: استدعاء Python من C#
\n\nPython هو ملك علم البيانات والتعلم الآلي. وإذا كان مشروعك على C# يتطلب، على سبيل المثال، تشغيل شبكة عصبية على PyTorch أو معالجة نصوص عبر spaCy، فإن استدعاء Python من C# عبر Python.NET هو ما تحتاجه.
\n\nالتثبيت والمثال الأول
\n\nنقوم بتثبيت الحزمة:
\n\ndotnet add package Python.Runtime.NETStandardالمدونات
توصيات الكتب
اقرأ أيضًا