Как разделить константу между кодом C# и C++?
Я пишу два процесса, используя C# и WCF для одного и C++ и WWSAPI для второго. Я хочу иметь возможность определить адрес, используемый для связи между ними в одном месте, и использовать его как C#, так и c++. Возможно ли это?
ближе всего я пришел к определению константы в IDL, а затем с помощью MIDL и TLBIMP, чтобы получить ее в DLL, которая может быть потреблена C#. Однако это, похоже, не разоблачает константу, или, по крайней мере, я не могу понять, как сделать это не так. Возможно, он ограничен только определениями типов.
какие-то другие предложения?
5 ответов
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/Invoke из C#.
вы можете создать отдельный проект C++/CLI и определить все константы в . Например, создайте проект библиотеки классов C++/CLI под названием "ConstantBridge" и проект c# под названием "CSharpProgram":
константы.h
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
project, зависимость времени выполнения не будет сгенерирована. Вы можете проверить, используя ILSpy или ILdasm. const
в C# и literal
в C++ / CLI являются скопировано "буквально" на сайт вызова во время компиляции.
не был доволен другими решениями для моего случая использования, поэтому закодировал немного хакерское решение, которое, похоже, лучше соответствует исходному запросу;константа в одном файле, которая может быть встроена в и проект C# и C++...
- информация о версии в a .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#, используя добавить существующий элемент... [Добавить Link]
- включить в проект C++ (в a .файл 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;
теперь, чтобы Visual Studio выполнила этот шаг, я не знаю, как это сделать. Вы должны будете исследовать, является ли это даже вероятный. Инструменты обработки текста UNIXy действительно стоит загрузить. У меня CygWin установлен на нескольких коробках, но, для чего-то такого локализованного, вы можете уйти с индивидуальным пакеты GnuWin32.
вы могли бы сделать подобную работу в PowerShell, но я не очень хорошо разбираюсь в этом.
теперь это немного kludge, поэтому я могу предложить, возможно, лучший способ для вас конкретного вопроса. Не использовать a постоянная вообще. Поместите адрес в файл конфигурации и попросите код C# и c++ прочитать его при запуске.
таким образом, вы можете поделиться значением безболезненно и он настраивается, если вы когда-нибудь захотите изменить его в будущем.
более простой альтернативой методу для каждой константы может быть класс, содержащий константы в качестве свойств экземпляра. Вы можете создать его на C# и предоставить его через COM-интерфейсы на C++. Это проще и менее подвержено ошибкам, чем P/Invoke, так как вам не нужно беспокоиться о том, чтобы получить все типы и имена правильно-все это делается для вас компилятором.
примечание: Я не пробовал это, я только предполагаю, что это должны работа.