У меня есть проект, который в основном написан на 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;
но в значительной степени повесили там.
1) Используйте препроцессор. Некоторые ifdefs и define должны справиться с задачей, но это было бы очень грязно.
2) Используйте C ++ / CLI. C ++ / CLI — это вариант C ++, который компилируется в сборки .Net. Хотя типы .Net и собственные типы являются отдельными объектами, возможны преобразования между ними.
Например, вы определяете заголовок как полностью нативный код с нативными перечислениями и константами; затем вы можете включить этот заголовок как в 100% собственный проект, так и в проект C ++ / CLI, который также обеспечит преобразования (увидеть эту тему) перечислений к соответствующим типам .Net.
Если вы не хотите иметь этот промежуточный уровень преобразования, C ++ / CLI также предоставляет вам все возможности макросов C ++, поэтому вы можете создать файл с макросами, такими как ENUM_HEADER и CONSTANT, и оценить их в соответствующие управляемые или собственные формы в довольно чистый и простой способ (что вы не можете сделать с C #, потому что он имеет гораздо более слабый препроцессор). Результирующая сборка будет тогда, по сути, этим заголовком и соответствующими определениями макросов и ничего больше
3) Имейте значения, определенные в каком-то внешнем файле (XML, INI, что угодно …) и реализуйте логику загрузки только в C # и C ++ (это может быть самым чистым решением).
Одним из вариантов является использование T4Это язык генерации кода, встроенный в Visual Studio. Это в основном используется в C #, но C ++ явно работает тоже.
Одна из причин, по которой вам будет трудно работать с препроцессором, состоит в том, что C # и C ++ имеют одинаковый синтаксис для комментариев: вы не сможете скрыть несовместимый специфичный для C # синтаксис для препроцессора C ++, используя комментарий. Тем не менее, вы можете попробовать VB :).