Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 添加属性时,如何保持.NET程序集的COM二进制兼容性?_C#_Com_Interop_Binary Compatibility - Fatal编程技术网

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

C# 添加属性时,如何保持.NET程序集的COM二进制兼容性?,c#,com,interop,binary-compatibility,C#,Com,Interop,Binary Compatibility,我们开发了一个.NET程序集,用于存储语言翻译信息,VB6应用程序需要使用它 我们希望能够在不必重新编译应用程序的情况下更改翻译信息 翻译由名为LanguageServices的两个文件部分类提供 一个文件是非更改库方法,另一个是从resx文件自动生成的所有属性,regx是从语言翻译信息数据库生成的 这一切都源于需要有一个翻译的中央数据库,该数据库可以通过编程“扁平化”为一种可以被我们每个不同应用程序使用的格式 现在,我可以通过绕过它并以不同的方式来解决这个问题。 事实上,我可以摆脱自动生成的属

我们开发了一个.NET程序集,用于存储语言翻译信息,VB6应用程序需要使用它

我们希望能够在不必重新编译应用程序的情况下更改翻译信息

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

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

这一切都源于需要有一个翻译的中央数据库,该数据库可以通过编程“扁平化”为一种可以被我们每个不同应用程序使用的格式

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

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

如果我们向数据库中添加新的翻译标签(这个单词中的这个单词变成了那个单词),它会向类中添加新的属性,从而向COM接口添加新的公开属性

[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; } 
}

属性在COM接口的中间添加,从而打破二进制兼容性。它们在中间被添加,因为C语言编译器用部分类的静态部分对部分类的动态部分进行后缀。我需要它做的是以另一种方式连接它们,或者在C#文件本身中显式地声明顺序。我认为在类的静态部分显式设置dispid可以做到这一点,但事实并非如此

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

这是添加新属性之前的IDL

以下是添加新属性并破坏兼容性后的IDL:

完全不同的是,这一位被挤到了中间:

[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);
我认为这就是问题所在,它改变了方法的顺序。我认为可以通过显式定义DispID来覆盖顺序(您可以看到
HRESULT区域性([in]ICultureInfo*pRetVal);
以后的所有内容都有一个从0开始的id

以下是编写/生成的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; } 
}
考虑到这一点,我可能只是让它不是一个分部类,只需将生成自动生成部分的xslt更改为包含静态部分。 它只是保持整洁分开

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

谢谢

J1M.

来自第10.2.6节

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

因此,c语言中没有规定控制类型成员的顺序,除了它们被声明的顺序。在部分声明的类型中,顺序是完全未定义的


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

仅当客户端代码使用后期绑定时才有效。显然不是。这是COM的致命弱点,v表排序至关重要。更改[Guid]是的,我认为这是最好的。是的,我最终停止了使用分部类。之后它才起作用。然而,由于我的DLL实际上是使用csc.exe命令行编译器而不是VS.NET编译的,我发现更改命令行中文件的顺序会影响分部类的接口创建顺序。但是不使用分部类是更简单的解决方案。