Подтвердить что ты не робот

С#, отображающий наследование интерфейса COM

Скажем, у меня есть класс BaseClass, который реализует IBaseClass

Затем у меня есть интерфейс IClass, который наследует IBaseClass.

Затем у меня есть класс с именем class, который реализует IClass.

Например:

[ComVisible(true), InterfaceType(ComInterfaceType.IsDual), Guid("XXXXXXX")]
public interface IBaseClass
{
  [PreserveSig]
  string GetA()
}

[ComVisible(true), InterfaceType(ComInterfaceType.IsDual), Guid("XXXXXXX")]  
public interface IClass : IBaseClass
{
  [PreserveSig]
  string GetB()
}

[ComVisible(true), ClassInterface(ClassInterfaceType.None), Guid("XXXXXXX")]
public class BaseClass : IBaseClass
{
  public string GetA() { return "A"; }
}

[ComVisible(true), ClassInterface(ClassInterfaceType.None), Guid("XXXXXXX")]
public class Class : BaseClass, IClass
{
  public string GetB() { return "B"; }
}

Когда выставляете COM, если я делаю экземпляр класса, он не позволяет мне вызвать GetA().

При поиске моего IDL в файле .tlb мой интерфейс IClass выглядит так:

[
  odl,
  uuid(XXXXXXXXXXXXXXXXXXXXX),
  version(1.0),
  dual,
  oleautomation,

]
interface IClass : IDispatch {
    [id(0x60020000)]
    BSTR GetB();
}

Это даже не похоже, что IClass происходит от IBaseClass!

Если я выберу, где IClass происходит из IBaseClass и просто добавляет методы в интерфейс, он работает.

Как я могу заставить С# включить это наследование в COM? Я бы предпочел не повторять реализацию интерфейсов, когда я могу их наследовать.

CRAP: проверьте эту ссылку .NET COM Limitation

Если у кого-то есть ответ на вопрос, почему это так, или лучше обходное решение, чем copy-paste для моего "производного" интерфейса, дайте мне знать. Если нет, я отвечу через пару дней.

4b9b3361

Ответ 1

Это не проблема .NET, это следствие того, как работает COM. Он не поддерживает наследование. Вы исправите это на стороне клиента, ему нужно вызвать QueryInterface() с IID для IBaseClass, чтобы получить указатель интерфейса на интерфейс IBaseClass, чтобы он мог вызвать GetA()..NET interop автоматически обеспечивает реализацию QI, которая делает эту работу. Тем не менее, в этом случае он не очень удобен в использовании, разработайте свой код на С#, чтобы клиент мог легко использовать ваш класс, а не наоборот. Обычно вам нужен метод переопределения с одним слоем, который делегирует базовую реализацию класса С#.

Обратите внимание, что существует проблема с сигнатурами вашего метода и использованием атрибута [PreserveSig]. Они не могут быть вызваны через IDispatch и не могут быть автоматически настроены. Для этого требуется метод с HRESULT в качестве типа возвращаемого значения. Это автоматически при удалении атрибута.

Ответ 2

Это похоже на этот вопрос: Наследование интерфейсов в классах ComVisible в С#

Как вы отметили в своем редактировании, это ограничение на .net to COM hop, что интерфейс COM не содержит никаких унаследованных интерфейсов.

На некоторых языках вы могли бы решить это, внедрив блок кода во все соответствующие интерфейсы, но насколько я могу видеть, это невозможно в С#.

Ответ 3

Вот другой подход, который минимизирует работу и оставляет интерфейс чистым.
Просто укажите дополнительное свойство, которое возвращает BaseInterface:

public IBaseClass BaseProperties {
    get { return this; }
}

Конечно, вы должны добавить эту часть в свой интерфейс IBaseClass:

public ISingleShot BaseProperties { get; }



Вот соответствующий код VB.Net:

ReadOnly Property BaseProperties As ISingleShot
Public ReadOnly Property BaseProperties As IBaseClass Implements IClass.BaseProperties
  Get
    Return Me
  End Get
End Property

Ответ 4

используйте [InterfaceType (ComInterfaceType.InterfaceIsIUnknown)] как атрибут для интерфейса, который расширяет остальные. это обходное решение.