سؤال

أنا أكتب عمليتين باستخدام C# و WCF لواحد و C ++ و WWSAPI للثاني. أريد أن أكون قادرًا على تحديد العنوان المستخدم للاتصال بين الاثنين في مكان واحد وأن يستخدمه كل من C# و C ++. هل هذا ممكن؟

أقرب ما أتيت هو تحديد الثابت في IDL ، ثم باستخدام MidL و Tlbimp للحصول عليه في DLL يمكن استهلاكه بواسطة C#. ومع ذلك ، لا يبدو أن هذا يفضح الثابت ، أو على الأقل لا يمكنني معرفة كيفية القيام بذلك. ربما يقتصر على نوع التعريفات فقط.

أي اقتراحات أخرى؟

هل كانت مفيدة؟

المحلول

C# و C ++ لها نماذج مختلفة للثوابت. عادة ، لن ينبعث الثابت في ثنائي C ++ الناتج - يتم استبداله تلقائيًا حيث يلزم الأمر معظم الوقت.

بدلاً من استخدام الثابت ، قم بعمل وظيفة تُرجع الثابت ، والتي يمكنك استدعاءها من C#.

هكذا،

#include <iostream>
const double ACCELERATION_DUE_TO_GRAVITY = 9.8;
int main()
{
     std::cout << "Acceleration due to gravity is: " << 
         ACCELERATION_DUE_TO_GRAVITY;
}

يصبح

#include <iostream>
extern "C" double AccelerationDueToGravity()
{
    return 9.8;
}
int main()
{
     std::cout << "Acceleration due to gravity is: " << 
         AccelerationDueToGravity();
}

الذي يجب أن تكون قادرًا على P/الاحتجاج من C#.

نصائح أخرى

يمكنك إنشاء مشروع C ++/CLI منفصل وتحديد جميع ثوابتك في أ .h ملف. على سبيل المثال ، قم بإنشاء مشروع مكتبة فئة C ++/CLI يسمى "ConstantBridge" ومشروع C# يسمى "Csharpprogram":

الثوابت

namespace Constants
{
    const int MAGIC_NUMBER = 42;
}

// String literals must be defined as macros
#define MAGIC_PHRASE "Hello World"

// Since stirngs must be macros it's arguably more consistent 
// to use `define` throughout. This is for demonstration purpose.

ConstantBridge.H

#include "Constants.h"

namespace ConstantBridge { public ref class ConstantBridge {
public:
    // The use of the `literal` keyword is important
    // `static const` will not work
    literal int kMagicNumber = Constants::MAGIC_NUMBER;
    literal String ^ kMagicPhrase = MAGIC_PHRASE;
};}

csharpprogram.cs

Console.WriteLine(ConstantBridge.kMagicNumber); // "42"
Console.WriteLine(ConstantBridge.kMagicPhrase); // "Hello World"

الآن ، لديك مشروع "Csharpprogram" يشير إلى مشروع "ConstantBridge". يمكن لمشاريع C ++ الأخرى الخاصة بك ببساطة #include "Constants.h".

طالما كنت تشير فقط literalق من ConstantBridge المشروع ، لن يتم إنشاء تبعية وقت التشغيل. يمكنك التحقق من استخدام ilspy أو ildasm. const في C# و literal في C ++/CLI نسخ "حرفيًا" إلى موقع الاتصال أثناء التجميع.

لم يكن سعيدًا بالحلول الأخرى لحالة الاستخدام الخاصة بي ، لذا فقد تم ترميز حل الاختراق قليلاً والذي يبدو أنه يناسب الطلب الأصلي بشكل أفضل ؛ ثابت في ملف واحد يمكن دمجه في على حد سواء A C# ومشروع C ++...

  1. معلومات الإصدار في ملف .cs ، في موقع مشترك.

مثله:

// Version.cs
public static class MyAppVersion
{
    //build
    public static string Number = "1.0";
    public static string Phase = "Alpha";

    //configuration (these are the build constants I use, substitute your own)
#if BUILD_SHIPPING
    public static string Configuration = "Shipping";
#elif BUILD_DEVELOPMENT
    public static string Configuration = "Development";
#elif BUILD_DEBUG
    public static string Configuration = "Debug";
#else
    "build type not defined"
#endif
}
  1. قم بتضمين في مشروع C# باستخدام إضافة عنصر موجود ... [إضافة كوصلة
  2. تضمين في مشروع C ++ (في ملف .cpp) مع أ #include

مثله:

//include version information into a .cpp
#define class namespace
#define public
#define static
#define string const char*
#include "..\..\Version.cs" //or to where-ever your file is
;
#undef class
#undef public
#undef static
#undef string
  1. الإشارة في C# مع: MyAppVersion.Number
  2. الإشارة في C ++ مع: MyAppVersion::Number

عندما اضطررت إلى القيام بهذه الأشياء في الماضي ، قمت ببساطة بإضافة خطوة إضافية قبل التثبيت إلى عملية الإنشاء التي تنشئ ملفًا من آخر بشكل تلقائي.

نظرًا لأن ثوابتك ستكون على الأرجح ضمن فصل دراسي في C#، يمكنك استخدام ذلك كملف المصدر:

MyClass.cs:
    class MyClass {
        public const int NUM_MONTHS = 12;    //COMMON
        public const int YEAR_BASE = 1900;   //COMMON
    }

grep '//COMMON' MyClass.cs
    | sed -e 's/^ *public const [a-z][a-z]*/#define/'
          -e 's/ *= */ /'
          -e 's/;.*$//'
    >MyClass.h
grep '//COMMON' MyClass.cs | sed -e 's/ *public //' -e 's/;.*$/;/' >MyClass.hpp

هذا سوف يعطيك:

MyClass.h:
    #define NUM_MONTHS 12
    #define YEAR_BASE 1900

MyClass.hpp:
    const int NUM_MONTHS = 12;
    const int YEAR_BASE = 1900;

الآن ، إن الحصول على Visual Studio لأداء هذه الخطوة ليس شيئًا أعرفه كيف أفعل. سيكون عليك التحقيق فيما إذا كان ذلك ممكنًا أم لا. أدوات معالجة النص Unixy تستحق التنزيل حقًا. أملك سيجوين تم تثبيتها على بعض الصناديق ولكن ، لشيء هذا المترجمة ، يمكنك الابتعاد عن الفرد حزم GNUWIN32.

ربما يمكنك القيام بعمل مماثل في PowerShell ، لكنني لست على دراية جيدة بذلك.


الآن هذا هو القليل من kludge ، لذلك قد أقترح طريقة أفضل لك سؤالًا معينًا. لا استعمال ثابت على الإطلاق. ضع العنوان في ملف التكوين واحصل على رمز C# و C ++ الخاص بك عند بدء التشغيل.

وبهذه الطريقة ، يمكنك مشاركة القيمة بشكل غير مؤلم و إنه قابل للتكوين في حال كنت ترغب في تغييره في المستقبل.

قد يكون بديل أسهل لطريقة لكل ثابت فئة تحتوي على الثوابت كخصائص مثيل. يمكنك إنشائه في C# وفضحه عبر واجهات COM إلى C ++. هذا أسهل وأقل عرضة للخطأ من P/Invoke ، حيث لا داعي للقلق بشأن الحصول على جميع الأنواع والأسماء بشكل صحيح - كل شيء يتم لكه المترجم.

ملاحظة: لم أجرب هذا ، أنا فقط أتكهن بذلك ينبغي الشغل.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top