Как сохранить двоичную совместимость COM для сборки .NET при добавлении свойств?

Мы разработали .NET Assembly, в которой хранится информация о языковых переводах, и она должна использоваться приложением VB6.

Мы хотели бы иметь возможность изменять информацию о переводе без перекомпиляции приложения.

Перевод обеспечивается двухфайловым частичным классом LanguageServices.

Один файл - это неизменяемые библиотечные методы, другой - все автоматически сгенерированные свойства из файла resx, а regx генерируется из базы данных с информацией о языковых переводах.

Все это возникло из-за необходимости иметь центральную базу данных переводов, которую можно было бы программно «сгладить» до формата, который может использоваться каждым из наших разрозненных приложений.

Теперь я могу решить эту проблему, обойдя ее и сделав это по-другому. На самом деле я мог бы просто избавиться от автоматически сгенерированного списка свойств, и проблема исчезла бы.

Меня интересует, как я могу решить эту проблему:

Если мы добавляем новые метки перевода в базу данных (ЭТО СЛОВО в ЭТОМ СЛОВЕ становится ЭТОМ СЛОВО), оно добавляет новые свойства к классу, который, в свою очередь, добавляет новые открытые свойства в COM-интерфейс.

Свойства добавляются в середине COM-интерфейса, нарушая двоичную совместимость.Они добавляются посередине, потому что компилятор C # добавляет суффиксы динамической части частичного класса к статической части частичного класса. Мне нужно либо объединить их наоборот, либо явно указать порядок в самих файлах C #. Я думал, что установка DispIDs явно в статической части класса сделает это, но этого не произошло.

Вот пара 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);

И я думаю , что проблема, это изменение порядка методов. Я думал, что порядок можно изменить, явно указав DispID (вы можете видеть, что все из HRESULT Culture ([in] ICultureInfo * pRetVal); и далее имеет идентификатор, начинающийся с 0.

Вот C # код, который был написан / сгенерирован: ILanguageServices.cs: автоматически сгенерированный интерфейс.

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

    /// 
    /// 
    /// 
    System.Boolean Offence_Regex { get; }

    /// 
    /// 
    /// 
    string Offence { get; }

    /// 
    /// 
    /// 
    System.Boolean Colour_ExactCaseMatch { get; }

    /// 
    /// 
    /// 
    System.Boolean Colour_Regex { get; }

    /// 
    /// 
    /// 
    string Colour { get; }

    /// 
    /// 
    /// 
    System.Boolean DebtManagementSystem_ExactCaseMatch { get; }

    /// 
    /// 
    /// 
    System.Boolean DebtManagementSystem_Regex { get; }

    /// 
    /// 
    /// 
    string DebtManagementSystem { get; }

    /// 
    /// 
    /// 
    System.Boolean DateOfContravention_ExactCaseMatch { get; }

    /// 
    /// 
    /// 
    System.Boolean DateOfContravention_Regex { get; }

    /// 
    /// 
    /// 
    string DateOfContravention { get; }

    /// 
    /// 
    /// 
    System.Boolean ContraventionDetails_ExactCaseMatch { get; }

    /// 
    /// 
    /// 
    System.Boolean ContraventionDetails_Regex { get; }

    /// 
    /// 
    /// 
    string ContraventionDetails { get; }

    /// 
    /// 
    /// 
    System.Boolean Income_ExactCaseMatch { get; }

    /// 
    /// 
    /// 
    System.Boolean Income_Regex { get; }

    /// 
    /// 
    /// 
    string Income { get; }

    /// 
    /// 
    /// 
    System.Boolean Hold_ExactCaseMatch { get; }

    /// 
    /// 
    /// 
    System.Boolean Hold_Regex { get; }

    /// 
    /// 
    /// 
    string Hold { get; }

    /// 
    /// 
    /// 
    System.Boolean CivilEnforcementOfficer_ExactCaseMatch { get; }

    /// 
    /// 
    /// 
    System.Boolean CivilEnforcementOfficer_Regex { get; }

    /// 
    /// 
    /// 
    string CivilEnforcementOfficer { get; }

    /// 
    /// 
    /// 
    System.Boolean PCNDebt_ExactCaseMatch { get; }

    /// 
    /// 
    /// 
    System.Boolean PCNDebt_Regex { get; }

    /// 
    /// 
    /// 
    string PCNDebt { get; }

    /// 
    /// 
    /// 
    System.Boolean OnHold_ExactCaseMatch { get; }

    /// 
    /// 
    /// 
    System.Boolean OnHold_Regex { get; }

    /// 
    /// 
    /// 
    string OnHold { get; }

    /// 
    /// 
    /// 
    System.Boolean DatePutOnHold_ExactCaseMatch { get; }

    /// 
    /// 
    /// 
    System.Boolean DatePutOnHold_Regex { get; }

    /// 
    /// 
    /// 
    string DatePutOnHold { get; }

    /// 
    /// 
    /// 
    System.Boolean HoldCode_ExactCaseMatch { get; }

    /// 
    /// 
    /// 
    System.Boolean HoldCode_Regex { get; }

    /// 
    /// 
    /// 
    string HoldCode { get; }

    /// 
    /// 
    /// 
    System.Boolean DateHoldExpires_ExactCaseMatch { get; }

    /// 
    /// 
    /// 
    System.Boolean DateHoldExpires_Regex { get; }

    /// 
    /// 
    /// 
    string DateHoldExpires { get; }

    /// 
    /// 
    /// 
    System.Boolean PutOnHoldByUserName_ExactCaseMatch { get; }

    /// 
    /// 
    /// 
    System.Boolean PutOnHoldByUserName_Regex { get; }

    /// 
    /// 
    /// 
    string PutOnHoldByUserName { get; }

    /// 
    /// 
    /// 
    System.Boolean CurrentState_ExactCaseMatch { get; }

    /// 
    /// 
    /// 
    System.Boolean CurrentState_Regex { get; }

    /// 
    /// 
    /// 
    string CurrentState { get; }

    /// 
    /// 
    /// 
    System.Boolean Vrm_ExactCaseMatch { get; }

    /// 
    /// 
    /// 
    System.Boolean Vrm_Regex { get; }

    /// 
    /// 
    /// 
    string Vrm { get; }

    /// 
    /// 
    /// 
    System.Boolean State_ExactCaseMatch { get; }

    /// 
    /// 
    /// 
    System.Boolean State_Regex { get; }

    /// 
    /// 
    /// 
    string State { get; }

    /// 
    /// 
    /// 
    System.Boolean CurrentStatechangedd2d2d4_ExactCaseMatch { get; }

    /// 
    /// 
    /// 
    System.Boolean CurrentStatechangedd2d2d4_Regex { get; }

    /// 
    /// 
    /// 
    string CurrentStatechangedd2d2d4 { get; }

    /// 
    /// 
    /// 
    System.Boolean SimonTest_ExactCaseMatch { get; }

    /// 
    /// 
    /// 
    System.Boolean SimonTest_Regex { get; }

    /// 
    /// 
    /// 
    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);
}

Подумав об этом, я, вероятно, мог бы просто сделать его не частичным class. Просто измените xslt, который сгенерировал автоматически сгенерированную часть, чтобы включить статическую часть. Было просто здорово сохранить его отдельно.

Тем не менее, может ли кто-нибудь мне сказать, почему он не работает и как сохранить более жесткий контроль над COM-интерфейсом? Строгое упорядочивание методов кажется таким ... черт возьми.

Спасибо,

J1M.

5
задан DaveInCaz 21 January 2019 в 12:38
поделиться