Совместное использование исходных файлов между C# и C++

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

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

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...

...

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

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

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


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

2 ответа

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

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

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

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

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

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

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

Другие вопросы по тегам