Как я могу разделить константу между C # и C ++?
-
01-10-2019 - |
Вопрос
Я пишу два процесса, используя C # и WCF для одного и C ++ и WWSAPI на второй. Я хочу быть в состоянии определить адрес, используемый для связи между двумя в одном месте, и используйте оба C #, так и C ++. Это возможно?
Самое близкое, которое я пришел, определяет константу в IDL, затем используя MIDL и TLBIMP, чтобы получить его в DLL, которая может потребляться C #. Однако это, похоже, не подвергает постоянную, или, по крайней мере, я не могу понять, как сделать это сделать это. Может быть, это ограничено только определениями типа.
Любые другие предложения?
Решение
C # и C ++ имеют различные модели для констант. Как правило, константу даже не будет выделяться в результате C ++ Binary - он автоматически заменяется там, где он необходим большую часть времени.
Вместо того, чтобы использовать константу, сделайте функцию, которая возвращает константу, которую вы можете P / вызывать из 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 #, называемый «CSHARPPROGR»:
Константы
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"
Теперь иметь проект «CSHARPPROGR» проект «Константабридж». Ваши другие нативные проекты C ++ могут просто #include "Constants.h"
.
До тех пор, пока вы ссылаетесь Только literal
с от ConstantBridge
Проект, зависимость выполнения не будет сгенерирована. Вы можете проверить, используя Ilspy. или Илды. const
в C # и literal
в C ++ / CLI скопирован «буквально» на сайт вызова во время компиляции.
Не было довольным с другими решениями для моего применения, настолько закодированы слегка халлическое решение, которое, кажется, соответствует первоначальному запросу лучше; постоянная в одном файле, который может быть встроен в обе C # и проект C ++...
- Информация о версии в файле .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
}
- Включите в проект C # с использованием добавления существующего элемента ... [Добавить в качестве ссылки
- Включают в проекте 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
- Ссылка в C # с:
MyAppVersion.Number
- Ссылка на 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;
Теперь, получая визуальную студию для выполнения этого шага - это не то, что я знаю, как сделать. Вам придется расследовать, можно ли ли это даже возможно. Инструменты обработки текста Unixy действительно стоит загружать. у меня есть Cygwin установлен на несколько коробок, но, для чего-то этого локализованного, вы можете сойти с индивидуальным Gnuwin32 пакеты.
Вы, вероятно, могли бы сделать подобную работу в PowerShell, но я не очень хорошо разбираюсь в этом.
Теперь это немного клюди, поэтому я могу предложить возможному лучшему способу для вашего конкретного вопроса. Нет использовать постоянно вообще. Поместите адрес в файл конфигурации и получите код C # и C ++, прочитайте его при запуске.
Таким образом, вы бесполезно поделитесь ценностью а также Это настраивается в том случае, если вы когда-нибудь хотите изменить его в будущем.
Простой альтернативой способе для каждой константы может представлять собой класс, содержащий константы в качестве свойств экземпляра. Вы можете создать его в C # и разоблачить его через COM-интерфейсы к C ++. Это легче и меньше ошибок, чем P / Invoke, поскольку вам не нужно беспокоиться о получении всех типов и имен вправо - все это сделано для вас компилятором.
Примечание: я не пробовал это, я только размышляю о том, что это должен работай.