【问题标题】:Sharing Source files between C# and C++在 C# 和 C++ 之间共享源文件
【发布时间】:2016-06-10 05:00:52
【问题描述】:

我有一个主要用 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 的最终整数值。)

我正在构建在 cmets 中看到的错误常量,我可以回到那个,但我宁愿编写类似的类 - 一个在 C# 中,一个在 C++ 中,可以构造/解构错误代码。我的函数返回错误的严重性、错误类等。开发者可以忽略它、记录它、将它传递给 UI 等等。

如果我只有 5 或 10 个错误代码,这不是问题。但我有超过 100 个,真的不想维护一个包含重复信息的 .cs 和 .h 文件。我可以在 .h 文件中管理它们并让 CS 代码读取它们,但这几乎与编写(修改)代码生成器一样多。


我怎样才能#define 获得单个源文件,以便 C# 编译器可以编译它,就像 C/++ 编译器一样?我可以简单地#include "ProjectErrors.cs" - 文件名在那里不是问题。我开始以为我可以通过#define'ing 像using System; 这样的东西来做到这一点,但几乎都挂在那里了。

【问题讨论】:

  • 大多数情况下,它只是将每个不在 C++ 中的单词和 #define 放在一个空白字符串中。我认为没有办法处理[Serializable]
  • 如您所说,代码生成器是一种解决方案。我认为没有其他方法
  • @DarkFalcon: #ifndef CPP \\\ [Serializable] \\\ #endif \\\ class XYZ { .... } 现在 #define CPP 仅在 C++ 端,并在 C# 端保持 CPP 未定义
  • @quetzalcoatl:当然可以,但这需要修改他的代码生成器。
  • 感谢 Dark Falcon,是的,实际上,[Serializable] 可能不需要,但由于它用于远程处理,我不确定......我真的希望这不是t 一个问题,如果项目更大,我会用 Native C++ 编写它,然后编写 C# 包装器.. 唉......

标签: c# c++ enums code-sharing


【解决方案1】:

1) 使用预处理器。一些 ifdef 和定义应该可以解决问题,但它会非常混乱。

2) 使用 C++/CLI。 C++/CLI 是 C++ 的一个变体,它被编译成 .Net 程序集。虽然 .Net 类型和本机类型是独立的实体,但它们之间的转换是可能的。

例如,您将标头定义为具有本机枚举和常量的完全本机代码;然后,您可以将此标头包含到 100% 本机项目和 C++/CLI 项目中,这还将提供枚举到相应 .Net 类型的转换 (see this thread)。

如果您不希望有这个中间转换层,C++/CLI 还为您提供了 C++ 宏的全部功能,因此您可以使用 ENUM_HEADER 和 CONSTANT 等宏创建一个文件,并将它们评估为适当的托管或本机以相当干净和直接的方式形成(你不能用 C# 来做,因为它的预处理器要弱得多)。生成的程序集基本上就是这个头文件和适当的宏定义,仅此而已。

3) 在某些外部文件(XML、INI 等)中定义值,并且只在 C# 和 C++ 中实现加载逻辑(这实际上可能是最简洁的解决方案)。

【讨论】:

    【解决方案2】:

    一种选择是使用T4:这是一种内置于 Visual Studio 中的代码生成语言。它主要用于C#,但C++ apparantly works too

    预处理器难以使用的原因之一是 C# 和 C++ 的 cmets 语法相同:您无法使用注释隐藏 C++ 预处理器的不兼容 C# 特定语法。也就是说,你可以试试 VB :)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-28
      • 2012-10-27
      • 2013-07-26
      • 2011-02-08
      • 1970-01-01
      • 2018-03-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多