我有一个主要用C#编写的项目。我需要为该项目的API的所有错误号“定义”定义一个类。我试图避免编写/修改我的许多代码生成器之一来实现这一目标。
我想做的是能够将#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...
...
我意识到还有其他东西可以放入Enums,但我的目标是能够用C ++编译器编译这个源代码。 (上面的示例中缺少函数,即ProjectErrCode()
,它在从API调用时构建错误代码OTF的最终整数值。)
我正在构建错误常量,如注释中所示,我可以回过头来看,但我更愿意编写类似的类 - 在C ++中用C#编写一个可以构造/解构错误代码的类。我的函数返回错误的严重性,错误类等。开发人员可以忽略它,记录它,将其传递给UI等等。
如果我只有5或10个错误代码,这不是问题。但我已经超过100,并且真的不希望维护带有重复信息的.cs和.h文件。我可以在.h文件中管理它们并让CS代码读取它们,但这几乎与编写(修改)代码生成器一样多。
我如何#define
通往单个源文件,以便C#编译器可以编译它,就像C / ++编译器一样?我可以简单地#include "ProjectErrors.cs"
- 文件名不是那里的问题。我开始认为我可以通过#define
像using System;
这样的东西来做这件事,但几乎挂了。
答案 0 :(得分:4)
1)使用预处理器。一些ifdef和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 ++中实现加载逻辑(这实际上可能是最干净的解决方案)。
答案 1 :(得分:4)
一种选择是使用T4:这是Visual Studio中内置的代码生成语言。它主要用于C#,但是C++ apparantly works too。
您在预处理器上遇到困难的原因之一是C#和C ++具有相同的注释语法:您无法使用注释为C ++预处理器隐藏不兼容的C#特定语法。也就是说,你可以尝试VB :)。