如何在包装器外部使用包装资源中的类型?

How can I use types from a wrapped resource outside of the wrapper?

我正在尝试包装 COM API,以便其他人可以使用我的包装器而无需了解包装的 API。但是,我在尝试使用 COM API.

中的某些项目时遇到了问题

假设 COM API 有一个方法 returns 在 API.

中定义的对象
IComChildObject IComObject.GetChildObject()

如果我有对定义 COM API 的 dll 的引用,我可以按如下方式轻松使用它...

IComChildObject childObject = myComObjectInstance.GetChildObject();

我遇到的问题是,我需要能够通过包装器 class 使用 IComChildObject,而不引用 COM API dll。

我试图在我的包装器中创建一个接口,它可以完成这个。所以在我的包装器项目中,我有一个这样的界面。

public interface ILocalChildObject : IComChildObject{}

然后我向我的包装器添加了一个 属性,我认为这将允许我的外部代码使用 IComChildObject。

public class ComWrapper
{
    IComObject comObject;

    public ILocalChildObject ComChildObject { get { return comObject.GetChildObject() as ILocalChildObject;}}
}

当我 运行 来自我的外部代码的以下代码时,ChildObject 为 null

ILocalChildObject ChildObject = myComWrapper.ComChildObject;

我显然做错了什么,但我对此一头雾水,甚至不知道要搜索什么 Google。

也许我不清楚我想做什么,或者我想在这里做一些奇怪的事情。我想以这种方式创建一个包装器 class 库,使用它的代码不必知道有关包装库的任何信息。到目前为止,我做得很好,直到我需要在外部代码中使用包装库中的对象。我可以通过在我的外部项目中引用包装库轻松解决这个问题,但我想避免这样做。

基本上,我只需要一种在我的外部代码中使用 IComChildObject 的方法,而不需要添加对 COM API dll 的引用。

如有任何帮助,我们将不胜感激,

如果你的API是基于IDispatch you could use the dynamic keyword,像这样:

dynamic childObject = GetChildObjectSomehow();
childObject.CallAnyMethod() // compile will always succeed, will be resolved at runtime (and failed if there's like a typo error)

注动态为not available on .NET core for COM objects yet

如果不是(如果它基于IUnknown),那么您必须在外部 dll 或 .tlb 中或直接在您的 C# 代码中声明此接口,以便可以调用由 .NET 运行时。你不必使用原来的.dll,如果需要你可以自己重新定义接口(也许是一个简化版本)。但是运行时必须知道二进制布局才能调用它。

正如 Hans Passant 指出的那样,另一种处理方法是将 COM API 对象包装在 class 中。然后就可以通过新对象访问对象内部的属性了。这种方法的唯一缺点是需要大量输入,因为您必须重新创建要在 COM API 对象中访问的任何属性或方法。

在包装器项目中,您将创建一个 class,它将包含从 API 返回的对象。此 class 还将具有属性和方法,允许用户通过 class.

操作 API 对象
public class LocalChildObject
{
    internal IComChildObject ComChildObject;
    
    public string ChildObjectProperty { get { reutrn ComChildObject.ChildObjectProperty; } set { ComChildObject.ChildObjectProperty = value ;}}
    
    public LocalChildObject(IComChildObject ComChildObject)
    {
        this.ComChildObject = ComChildObject;
    }
}

在此示例中,ComChildObject 是从 API 返回的对象。然后在classChildObjectProperty中有一个属性,它允许你获取或设置ComChildObjectChildObjectProperty

然后在我的主包装器 class 中,我可以有一个 属性 这个 returns 这个新对象(它包含 API COM 对象)。

public class Wrapper
{
    public LocalChildObject GetLocalChildObject { get { return new LocalChildObject(ComObject.GetChildComObject());}}
}

然后在外部代码中我可以通过新的包装器对象对对象进行更改

LocalChildObject localObject = myWrapperInstance.GetLocalChildObject;
localObject.ChildObjectProperty = "A new string";

此方法需要重新创建要通过包装器公开的所有属性和方法,但是,它允许使用包装器的用户使用 IntelliSense。