添加属性时,如何保留 .NET 程序集的 COM 二进制兼容性?

2023-11-23

我们开发了一个 .NET 程序集来存储语言翻译信息,并且需要由 VB6 应用程序使用。

我们希望能够更改翻译信息而无需重新编译应用程序。

翻译由名为 LanguageServices 的两个文件部分类提供。

一个文件是不变的库方法,另一个文件是从 resx 文件自动生成的所有属性,而 regx 是从语言翻译信息数据库生成的。

这一切都源于对一个中央翻译数据库的需求,该数据库可以通过编程方式“扁平化”为每个不同应用程序都可以使用的格式。

现在,我可以通过绕过它并以不同的方式来解决这个问题。 事实上,我可以去掉自动生成的属性列表,问题就会消失。

我感兴趣的是如何解决这个问题,即:

如果我们向数据库添加新的翻译标签(THIS WORD 中的 THIS WORD 变为 THAT WORD),它将向类添加新属性,而类又向 COM 接口添加新的公开属性。

这些属性被添加到 COM 接口的中间,从而破坏了二进制兼容性。它们被添加在中间,因为 C# 编译器将分部类的动态部分添加到分部类的静态部分后缀。我需要它做的是要么以相反的方式连接它们,要么在 C# 文件本身中明确说明顺序。我认为在类的静态部分显式设置 DispID 可以做到这一点,但事实并非如此。

以下是构建过程生成的一对 IDL 文件:

这是添加新属性之前的 IDL。

http://pastebin.com/qPvcUV9z

这是添加新属性并且兼容性被破坏后的 IDL:

http://pastebin.com/K2MuqtYV

确切的区别是这一点被推到了中间:

[id(0x60020039), propget]
HRESULT Jn_ExactCaseMatch([out, retval] VARIANT_BOOL* pRetVal);
[id(0x6002003a), propget]
HRESULT Jn_Regex([out, retval] VARIANT_BOOL* pRetVal);
[id(0x6002003b), propget]
HRESULT Jn([out, retval] BSTR* pRetVal);

And I think这就是问题所在,它改变了方法的顺序。我认为可以通过显式定义 DispID 来覆盖该顺序(您可以看到来自HRESULT Culture([in] ICultureInfo* pRetVal);以后的 id 从 0 开始。

以下是编写/生成的 C# 代码: ILanguageServices.cs:自动生成的接口。

[Guid("547a7f6e-eeda-4f77-94d0-2dd24f38ba58")]
public partial interface ILanguageServices
{
    /// <summary>
    /// 
    /// </summary>
    System.Boolean Offence_ExactCaseMatch { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean Offence_Regex { get; }

    /// <summary>
    /// 
    /// </summary>
    string Offence { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean Colour_ExactCaseMatch { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean Colour_Regex { get; }

    /// <summary>
    /// 
    /// </summary>
    string Colour { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean DebtManagementSystem_ExactCaseMatch { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean DebtManagementSystem_Regex { get; }

    /// <summary>
    /// 
    /// </summary>
    string DebtManagementSystem { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean DateOfContravention_ExactCaseMatch { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean DateOfContravention_Regex { get; }

    /// <summary>
    /// 
    /// </summary>
    string DateOfContravention { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean ContraventionDetails_ExactCaseMatch { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean ContraventionDetails_Regex { get; }

    /// <summary>
    /// 
    /// </summary>
    string ContraventionDetails { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean Income_ExactCaseMatch { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean Income_Regex { get; }

    /// <summary>
    /// 
    /// </summary>
    string Income { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean Hold_ExactCaseMatch { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean Hold_Regex { get; }

    /// <summary>
    /// 
    /// </summary>
    string Hold { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean CivilEnforcementOfficer_ExactCaseMatch { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean CivilEnforcementOfficer_Regex { get; }

    /// <summary>
    /// 
    /// </summary>
    string CivilEnforcementOfficer { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean PCNDebt_ExactCaseMatch { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean PCNDebt_Regex { get; }

    /// <summary>
    /// 
    /// </summary>
    string PCNDebt { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean OnHold_ExactCaseMatch { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean OnHold_Regex { get; }

    /// <summary>
    /// 
    /// </summary>
    string OnHold { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean DatePutOnHold_ExactCaseMatch { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean DatePutOnHold_Regex { get; }

    /// <summary>
    /// 
    /// </summary>
    string DatePutOnHold { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean HoldCode_ExactCaseMatch { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean HoldCode_Regex { get; }

    /// <summary>
    /// 
    /// </summary>
    string HoldCode { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean DateHoldExpires_ExactCaseMatch { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean DateHoldExpires_Regex { get; }

    /// <summary>
    /// 
    /// </summary>
    string DateHoldExpires { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean PutOnHoldByUserName_ExactCaseMatch { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean PutOnHoldByUserName_Regex { get; }

    /// <summary>
    /// 
    /// </summary>
    string PutOnHoldByUserName { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean CurrentState_ExactCaseMatch { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean CurrentState_Regex { get; }

    /// <summary>
    /// 
    /// </summary>
    string CurrentState { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean Vrm_ExactCaseMatch { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean Vrm_Regex { get; }

    /// <summary>
    /// 
    /// </summary>
    string Vrm { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean State_ExactCaseMatch { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean State_Regex { get; }

    /// <summary>
    /// 
    /// </summary>
    string State { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean CurrentStatechangedd2d2d4_ExactCaseMatch { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean CurrentStatechangedd2d2d4_Regex { get; }

    /// <summary>
    /// 
    /// </summary>
    string CurrentStatechangedd2d2d4 { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean SimonTest_ExactCaseMatch { get; }

    /// <summary>
    /// 
    /// </summary>
    System.Boolean SimonTest_Regex { get; }

    /// <summary>
    /// 
    /// </summary>
    string SimonTest { get; } 
}

ILanguageServices_Static.cs:界面中不变的部分

public partial interface ILanguageServices
{
    [DispId(0)]
    ICultureInfo Culture { get; set; }
    [DispId(1)]
    IResourceManager ResourceManager { get; }
    [DispId(2)]
    ICultureInfo[] GetCultures(System.Globalization.CultureTypes enCultureTypes);
    [DispId(3)]
    ICultureInfo GetCultureInfo(int LCID);
    [DispId(4)]
    ICultureInfo CurrentCulture { get; }
    [DispId(5)]
    string TranslateString(string rawString, bool searchInsideString);
    [DispId(6)]
    string TranslateString(string rawString);
}

想一想,我可能可以让它不成为一个部分课程。只需更改生成自动生成部分的 xslt 以包含静态部分。 把它分开真是太好了。

不管怎样,有人能告诉我为什么它不起作用以及如何对 COM 接口保持更严格的控制吗? 严格排序方法似乎是这样...... 布鲁夫。

Thanks,

J1M.


来自C# 语言规范版本 4第 10.2.6 节:

类型中成员的顺序对于 C# 代码来说很少很重要,但在与其他语言和环境交互时可能很重要。在这些情况下,在多个部分中声明的类型中成员的顺序是未定义的。

因此,除了声明顺序之外,C# 语言中没有任何规定来控制类型成员的顺序。在部分声明的类型中,顺序是完全未定义的。

因此,这里的结论是不要对要向 COM 公开的接口使用部分声明。无法控制接口成员顺序,并且由于其在语言中未定义,因此生成的成员顺序可能随时更改。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

添加属性时,如何保留 .NET 程序集的 COM 二进制兼容性? 的相关文章

随机推荐

  • 序列化可选的 where 子句参数?

    这是一件让我真正烦恼的事情 我必须为几乎相同的查询编写两个不同的函数 假设我有一个返回的 APIposts与特定的相关联typeId and cityId 要得到ALL相关帖子typeId 1 OR 2 OR 3 and cityId 1我
  • VB.NET静态代码分析

    有谁知道 vb net 的良好代码静态代码分析吗 我见过很多关于 c 的内容 我认为 VS 2008 内置了一些 但我们目前只使用 vs 2005 FxCop就是这么做的 具体针对 VB NET 的是项目分析器
  • 如何从 html 按钮调用 Firefox 扩展中的函数

    如何使用网页中的 html 按钮调用在我的扩展中声明的 Javascript 函数 我有一个 html 页面 里面有一个按钮 当用户单击该按钮时 它将调用我已经在自己的 Firefox 扩展中声明的函数 由于您控制网页 因此执行您想要的操作
  • 按共享列值合并关联数组的数组[重复]

    这个问题在这里已经有答案了 我想根据公共列值合并两个数组 这是我的 2 个数组 array1 total process per category gt 6 category id gt 1 total process per catego
  • 如何使用 NSDistributedNotifications 在进程之间共享核心数据存储?

    背景 我已经发布了一个关于基础知识的问题在进程之间共享核心数据存储 我正在尝试实施给出的建议 但遇到了问题 My Goal 我有两个进程 Helper App 和 UI 它们都共享一个数据存储 当助手应用程序将新数据保存到商店时 我希望 U
  • 如何在 R 中重命名具有特定模式的文件?

    有一些 fcs文件在一个数据 000X目录中的格式 其中 X 1 2 3 我想重命名每个n文件格式如下 exp fcs where exp是来自向量的文本 如果要重命名的文件是 fcs file 换句话说 我想将文件重命名为exp txt
  • 将 PCAP 跟踪转换为 NetFlow 格式

    我想将一些 PCAP 跟踪转换为 Netflow 格式 以便使用 netflow 工具进行进一步分析 有什么办法可以做到这一点吗 具体来说 我想使用 flow export 工具从 netflow 跟踪中提取一些感兴趣的字段 如下所示 fl
  • php 中用于缩小/压缩 javascript 的简单正则表达式搜索和替换?

    你能在 php 中发布正则表达式搜索和替换来缩小 压缩 javascript 吗 例如 这是一个简单的 CSS header Content type text css ob start compress function compress
  • Java 正则表达式 - 重叠匹配

    在下面的代码中 public static void main String args List
  • Java正则表达式精确匹配8位数字

    我有一个简单的正则表达式 应该查找 8 位数字 String number scanner findInLine d 8 但事实证明 它也匹配9位或更多位的数字 如何修复此正则表达式以精确匹配 8 位数字 例如 12345678应该匹配 而
  • 安装镶木地板工具

    我正在尝试在 FreeBSD 机器上安装 parquet 工具 我克隆了这个仓库 git clone https github com apache parquet mr 然后我做了cd parquet mr parquet tools 然
  • 在 OCUnit 中使用核心数据类时出现 Apple Mach-O 链接器错误

    好的 这是我的测试类中的代码 NSManagedObjectContext managedObjectContextWithConcurrencyType NSManagedObjectContextConcurrencyType conc
  • 什么是 CSRF 代币?它的重要性是什么?它是如何运作的?

    我正在编写一个应用程序 Django 确实如此 我只想了解 CSRF 令牌 实际上是什么以及它如何保护数据 如果不使用CSRF token 发布的数据会不安全吗 简单来说 跨站请求伪造 CSRF 假设您当前已登录网上银行 www myban
  • 在 MySql 中将 VARCHAR 转换为 DECIMAL 值

    我已将包含字符串值 例如吃 和浮动值 例如 0 87 的 CSV 文件导入到我的 phpMyAdmin 数据库中的表中 在处理完所有字符串值并仅保留具有十进制值的行后 我需要将这些值从 VARCHAR 转换为 DECIMAL FLOAT 以
  • 定点的反平方根

    我正在寻找定点 16 16 数字的最佳反平方根算法 下面的代码是我到目前为止所拥有的 但基本上它取平方根并除以原始数字 我想得到不除法的倒数平方根 如果它发生任何改变 代码将为armv5te编译 uint32 t INVSQRT uint3
  • 为什么使用 static_cast(x) 而不是 (T)x?

    我听说static cast函数应该优先于 C 风格或简单函数风格的转换 这是真的 为什么 主要原因是经典的 C 类型转换不区分我们所说的static cast lt gt reinterpret cast lt gt const cast
  • 确定为特定函数调用分派哪个方法

    我试图理解一些我没有编写的代码 plot gam在 mgcv 中 并且有一个调用plot 函数带有一些我不认识的奇怪参数 例如 P 我想弄清楚这次调用正在调度哪个绘图方法 findMethod 和类似的功能没有帮助 我认为情节是S3 我尝试
  • php shell_exec 权限被拒绝

    shell exec touch Users Nerses Downloads ads txt 2 gt 1 我的 PHP exec shel exec 函数有问题 它说我没有执行该命令的权限 怎样才能打开这些权限呢 您的 PHP 代码正在
  • sql 2008 中没有索引的表列表

    如何列出 SQL 2008 数据库中没有索引的表 Edit我想要架构名称和表名称 这应该涵盖您正在寻找的内容 即堆表 无聚集索引 并且没有任何非聚集索引 它使用新的系统 2005 2008 年使用的表对象 此外 您可能想要查找具有聚集索引但
  • 添加属性时,如何保留 .NET 程序集的 COM 二进制兼容性?

    我们开发了一个 NET 程序集来存储语言翻译信息 并且需要由 VB6 应用程序使用 我们希望能够更改翻译信息而无需重新编译应用程序 翻译由名为 LanguageServices 的两个文件部分类提供 一个文件是不变的库方法 另一个文件是从