Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/320.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# 如何使用包装器之外的包装资源中的类型?_C#_Com_Wrapper - Fatal编程技术网

C# 如何使用包装器之外的包装资源中的类型?

C# 如何使用包装器之外的包装资源中的类型?,c#,com,wrapper,C#,Com,Wrapper,我正在尝试包装一个COM API,这样其他人就可以使用我的包装器,而不必了解包装的API。但是,我在尝试使用COM API中的一些项时遇到了一个问题 假设COM API有一个返回API中定义的对象的方法 IComChildObject IComObject.GetChildObject() 如果我有一个对定义COM API的dll的引用,我可以很容易地如下使用它 IComChildObject childObject = myComObjectInstance.GetChildObject()

我正在尝试包装一个COM API,这样其他人就可以使用我的包装器,而不必了解包装的API。但是,我在尝试使用COM API中的一些项时遇到了一个问题

假设COM API有一个返回API中定义的对象的方法

IComChildObject IComObject.GetChildObject()
如果我有一个对定义COM API的dll的引用,我可以很容易地如下使用它

IComChildObject childObject = myComObjectInstance.GetChildObject();
我的问题是,我需要能够通过包装器类使用IComChildObject,而无需引用COM API dll

我试图在我的包装器中创建一个接口,这将实现这一点。所以在我的包装器项目中,我有一个这样的接口

public interface ILocalChildObject : IComChildObject{}
然后我在包装器中添加了一个属性,我认为这将允许我的外部代码使用IComChildObject

public class ComWrapper
{
    IComObject comObject;

    public ILocalChildObject ComChildObject { get { return comObject.GetChildObject() as ILocalChildObject;}}
}
当我从外部代码运行以下代码时,
ChildObject
为空

ILocalChildObject ChildObject = myComWrapper.ComChildObject;
我显然做错了什么,但我在这件事上不知所措,甚至不知道该在谷歌搜索什么

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

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

非常感谢您的帮助,

如果您的API基于,您可以使用,如下所示:

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


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

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

在包装器项目中,您将创建一个类,该类将包含从API返回的对象。该类还将具有属性和方法,允许用户通过该类操作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返回的对象。然后类
ChildObjectProperty
中有一个属性,它允许您获取或设置
ComChildObject
ChildObjectProperty

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

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

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

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

如果您的API基于IDispatch,则可以使用
dynamic
关键字(尚未在.NET core上)或键入.Invoke(“名称”)。如果不是(如果它基于IUnknown),则必须在外部dll或.tlb中声明此接口,或直接在C#代码中声明此接口,以便.NET运行时调用它。@SimonMourier感谢您的帮助。我如何知道API是基于什么的?我不能控制API,我只能通过COM访问它。我唯一可以更改的代码是包装器代码,以及使用包装器的代码。@SimonMourier谢谢您的帮助。我使用了dynamic,它很有效。如果您将注释转换为答案,我将接受它作为正确答案。接口不是包装器,不会隔离互操作程序集引用。你需要上课。假设ChildWrapper具有IComChildObject类型的私有字段。就像你对ComWrapper做的一样。这确实会让人感到无聊,当您看到自己不得不用一行代码复制所有子对象属性和方法时,您会开始想,这有什么意义。倾向于了解更多关于您包装的库的信息,但这不起作用。这似乎是最简单的解决方案。但是,它不允许包装器的使用者使用IntelliSense查看对象的方法和属性。目前这可能是可以接受的,但我将继续寻找一种解决方案,使他们能够更轻松地创建代码。再次感谢我们的帮助。@Tim-若要使用intellisense作为COM对象,这意味着您必须以某种方式使用.tlb。你的COM API有一个.tlb吗?您可能会这样做,因为当您使用.dll时,intellisense正在工作。在这种情况下,您可以只导出.tlb和.NET用户可以引用它而不是.dll。它们将只包含元数据,而不包含代码。
LocalChildObject localObject = myWrapperInstance.GetLocalChildObject;
localObject.ChildObjectProperty = "A new string";