简体   繁体   English

C#暴露给COM - 接口继承

[英]C# exposing to COM - interface inheritance

Say I have a class BaseClass that implements IBaseClass 假设我有一个实现IBaseClass的类BaseClass

Then I have an interface IClass that inherits IBaseClass. 然后我有一个继承IBaseClass的接口IClass。

Then I have a class named class that implements IClass. 然后我有一个名为class的类,它实现了IClass。

For example: 例如:

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

When exposing to COM, if I make an instance of "Class" it does not allow me to call GetA(). 当暴露给COM时,如果我创建一个“Class”实例,它就不允许我调用GetA()。

When looking my IDL in the .tlb file, my IClass interface looks like: 在.tlb文件中查找我的IDL时,我的IClass界面如下所示:

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

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

It doesn't even look like IClass derives from IBaseClass! 它甚至看起来像IClass派生自IBaseClass!

If I take out where IClass derives from IBaseClass and just add the methods to the interface, it works. 如果我拿出IClass从IBaseClass派生的地方,只是将方法添加到接口,它就可以工作。

How can I make C# enable this inheritance in COM? 如何让C#在COM中启用此继承? I'd rather not re-implement interfaces when I can inherit them. 当我可以继承接口时,我宁愿不重新实现接口。

CRAP: check this link .Net COM Limitation CRAP:检查此链接.Net COM限制

If someone has an answer to why this is, or a better workaround than copy-paste to my "derived" interface, let me know. 如果有人能够解答为什么会这样,或者比将其复制粘贴到我的“派生”界面更好的解决方法,请告诉我。 If not, I'll mark an answer in a couple days. 如果没有,我会在几天内给出答案。

This is not a .NET problem, it is a consequence of the way COM works. 这不是.NET问题,它是COM工作方式的结果。 It doesn't support inheritance. 它不支持继承。 You would fix this at the client side, it needs to call QueryInterface() with the IID for IBaseClass to get an interface pointer to the IBaseClass interface so it can call GetA(). 您可以在客户端修复此问题,它需要使用IBaseClass的IID调用QueryInterface()以获取指向IBaseClass接口的接口指针,以便它可以调用GetA()。 .NET interop automatically provides a QI implementation that makes this work. .NET interop自动提供一个QI实现,使其工作。 However, it is not very user-friendly in this case, design your C# side code to make it easy for the client to use your class instead of the other way around. 但是,在这种情况下,它不是非常用户友好,设计您的C#端代码使客户端可以轻松使用您的类而不是相反。 You'd typically need a one-liner override method that delegates to the base C# class implementation. 您通常需要一个单行覆盖方法,该方法委托给基本C#类实现。

Note that there's a problem with your method signatures and the use of the [PreserveSig] attribute. 请注意,您的方法签名和[PreserveSig]属性的使用存在问题。 They are not callable through IDispatch nor can they be auto-marshaled. 它们不能通过IDispatch调用,也不能自动编组。 That requires a method with a HRESULT as the return value type. 这需要一个HRESULT作为返回值类型的方法。 It is automatic when you remove the attribute. 删除属性时会自动进行。

This appears to be very similar to this question: Interface inheritance in ComVisible classes in C# 这似乎与这个问题非常相似: C#中的ComVisible类中的接口继承

As you noted in your edit, this is a limitation on the .net to COM hop, that the COM interface does not include any inherited interfaces. 正如您在编辑中所指出的,这是对.com到COM跳的限制,COM接口不包含任何继承的接口。

In some languages you could have solved this by inculding a block of code in all relevant interfaces, but as far as I am able to see this is not possible in C#. 在某些语言中,你可以通过在所有相关接口中包含一段代码来解决这个问题,但据我所知,这在C#中是不可能的。

Here is a different Approach that minimizes the work, and leaves the interface clean. 这是一种不同的方法,可以最大限度地减少工作量,并使界面保持干净。
Just provide an additional Property which returns the BaseInterface: 只需提供一个返回BaseInterface的附加属性:

public IBaseClass BaseProperties {
    get { return this; }
}

Of course you have to add thise part in your IBaseClass Interface: 当然,你必须在你的IBaseClass接口中添加这个部分:

public ISingleShot BaseProperties { get; }



Here is the corresponding VB.Net Code: 这是相应的VB.Net代码:

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

use [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] as an attribute for the interface that extends the others. 使用[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]作为扩展其他接口的接口的属性。 it is a workaround. 这是一种解决方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM