2013-11-11 9 views
6

У меня есть проект, который в основном написан на C#. Мне нужно определить класс для всего номера ошибки «определяет» для API этого проекта. Я пытаюсь избежать написания/изменения одного из моих многочисленных генераторов кода для достижения этого.Обмен исходными файлами между C# и C++

Я хотел бы сделать это с #include (например, ошибкой ошибки) непосредственно в проекте C/C++. Я определил их в C#, как следует, и я не использовал перечисление для вещей, которые вы увидите здесь:

using System; 

namespace ProjectAPI { 

[Serializable] 
public sealed class ProjectError { 

    public enum ProjectErrorClass { 
     None   = -1, 
     Undefined  = 0, 
     Login, 
     Store, 
     Transaction, 
     Heartbeat, 
     Service, 
     HTTPS, 
     Uploader, 
     Downloader, 
     APICall, 
     AutoUpdate, 
     General 
    } 

    public enum ProjectErrorLevel { 
     Unknown = -1, 
     Success = 0, 
     Informational, 
     Warning, 
     Critical, 
    }; 

    /// <summary> 
    /// PROJECT_ERROR_BASE - This is the base for all Project defined errors in the API. Project Errors are defined as follows: 
    /// ProjectAPI error values are 32 bit values defined as follows: 
    /// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 
    /// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 
    /// +---+---------------+-----------------------+------------------+ 
    /// |Sev|Error Code Base| Error Class   |Unique Error Code | 
    /// +---+---------------+-----------------------+------------------+ 
    /// where 
    /// 
    ///  Sev - is the severity code of the error (2 bits), and is defined as follows: 
    ///   00 - Success (non-fatal) 0x00 
    ///   01 - Informational   0x01 
    ///   10 - Warning    0x02 
    ///   11 - Error     0x03 
    /// 
    ///  Error Code Base - is the starting point of all Project Errors, and is set at 0xA4 (8 Bits). 
    /// 
    ///  Error Class - is the error class, or API "Module" that caused the error (12 bits). 
    /// 
    ///  Code - the unique error code (10 bits). (0 - 1,023 (0x3FF)). 
    /// </summary> 

    private static readonly int ERR_SHIFT      = 0x1E; 
    private static readonly int BASE_SHIFT      = 0x16; 
    private static readonly int CLASS_SHIFT      = 0x06; 

    private static readonly int PROJECT_SEV_SUCCESS   = 0x00; 
    private static readonly int PROJECT_SEV_INFO    = 0x01; 
    private static readonly int PROJECT_SEV_WARN    = 0x02; 
    private static readonly int PROJECT_SEV_ERROR    = 0x03; 

    private static readonly int PROJECT_ERROR_BASE    = 0xA5; 

    /// <summary> 
    /// Project Error Class Constants: 
    /// </summary> 
    private static readonly int PROJECT_ERROR_CLASS_UNDEF  = 0x0010; /// Undefined. 
    private static readonly int PROJECT_ERROR_CLASS_LOGIN  = 0x0020; /// LoginClass Error. 
    private static readonly int PROJECT_ERROR_CLASS_STORE  = 0x0040; /// Store Error. 
    private static readonly int PROJECT_ERROR_CLASS_TRANS  = 0x0080; /// Transaction Error. 
    private static readonly int PROJECT_ERROR_CLASS_HEART  = 0x0100; /// HeartBeat (Project Health Monitor) Error. 
    private static readonly int PROJECT_ERROR_CLASS_SERV  = 0x0200; /// Service Error. 
    private static readonly int PROJECT_ERROR_CLASS_HTTP  = 0x0400; /// HTTP/HTTPS Error. 
    private static readonly int PROJECT_ERROR_CLASS_UPLOAD = 0x0800; /// Upload (Transactions) Error 
    private static readonly int PROJECT_ERROR_CLASS_DOWNLOAD = 0x1000; /// Download (Transactions) Error 
    private static readonly int PROJECT_ERROR_CLASS_APICALL = 0x2000; /// API Command/call error. 
    private static readonly int PROJECT_ERROR_CLASS_UPDATE = 0x4000; /// Auto-Updater Errors. 
    private static readonly int PROJECT_ERROR_CLASS_GEN  = 0x8000; /// General Error. 

    public static readonly int PROJECT_ERROR_UNKNOWN_ERROR = ProjectErrCode(PROJECT_SEV_ERROR, PROJECT_ERROR_CLASS_GEN, 0x001); 
    // Was... 
    // (((PROJECT_SEV_ERROR << ERR_SHIFT) | PROJECT_ERROR_BASE << BASE_SHIFT) | ((PROJECT_ERROR_CLASS_UNDEF << CLASS_SHIFT) | 0x0001)); 

    public static readonly int PROJECT_ERROR_UNKNOWN_HEARTBEAT_ERROR = ProjectErrCode(PROJECT_SEV_ERROR, PROJECT_ERROR_CLASS_HEART, 0x001); 
...Snip... 

...

Я понимаю, что есть другие вещи, которые я мог бы поставить в Перечисление, однако мой Цель состоит в том, чтобы иметь возможность компилировать этот источник с помощью компилятора C++. (В приведенном выше примере отсутствуют функции, а именно ProjectErrCode(), который строит окончательное целочисленное значение кода ошибки OTF при вызове из API.)

Я создавал константы ошибок, как видно из комментариев, и могу вернемся к этому, но я бы предпочел написать аналогичные классы - один в C# один в C++, который может конструировать/деконструировать коды ошибок. Мои функции возвращают серьезность ошибки, класс ошибки и т. Д. Разработчик может игнорировать его, регистрировать, передавать его в пользовательский интерфейс и т. Д.

Если у меня было только 5 или 10 кодов ошибок, это не проблема. Но мне больше 100 и действительно не хочу, чтобы поддерживать файлы .cs и .h с дублирующейся информацией. Я могу управлять ими в файле .h и читать код CS, но это почти такая же работа, как и запись (модификация) генератора кода.


Как я могу #define свой путь к одному исходному файлу, так что C# компилятор может скомпилировать его, точно так же, как и/++ компилятор C может, а? Я мог просто просто #include "ProjectErrors.cs" - Имя файла здесь не проблема. Я начал думать, что могу это сделать, например, , но в значительной степени его повесили.

+1

В основном это было бы просто взять каждое слово, которое не находится на C++, а '# define' - пустую строку. Я не вижу возможности справиться с '[Serializable]'. –

+2

Как вы сказали, генератор кода является решением. Я не думаю, что есть другой способ: – Matt

+1

@DarkFalcon: '#ifndef CPP \\\ [Serializable] \\\ #endif \\\ класс XYZ {....}' и теперь '#define CPP' только на стороне C++ , и удерживайте CPP на стороне C# – quetzalcoatl

ответ

4

1) Используйте препроцессор. Некоторые ifdefs и define должны делать трюк, но это было бы очень грязно.

2) Используйте C++/CLI. C++/CLI - это вариант C++, который скомпилирован в сборки .Net. Хотя типы .Net и собственные типы являются отдельными объектами, возможны переходы между ними.

Например, вы определяете заголовок как полностью собственный код с собственными перечислениями и константами; вы можете включить этот заголовок как в 100% -ный проект, так и в проект C++/CLI, который также обеспечит преобразования (see this thread) перечислений в соответствующие типы .Net.

Если вы не хотите иметь этот промежуточный уровень конверсии, C++/CLI также дает вам полную мощь макросов C++, поэтому вы можете создать файл с такими макросами, как ENUM_HEADER и CONSTANT, и оценить их в соответствующих управляемых или (что вы не можете сделать с C#, потому что он имеет гораздо более слабый препроцессор). Результатом сборки будет, по существу, этот заголовок и соответствующие макроопределения, и ничего больше.

3) Определите значения, определенные в каком-либо внешнем файле (XML, INI, независимо ...) и реализуйте логику загрузки как на C#, так и на C++ (это действительно может быть самым чистым решением).

4

Одним из вариантов является использование T4: это язык генерации кода, встроенный в Visual Studio. Он в основном используется в C#, но C++ apparantly works too.

Одна из причин, по которой вам трудно работать с препроцессором, заключается в том, что C# и C++ имеют одинаковый синтаксис для комментариев: вы не сможете скрыть несовместимый синтаксис C# для препроцессора C++, используя комментарий. Тем не менее, вы можете попробовать VB :).

Смежные вопросы