1

我有一个从另一个接口继承的接口,如下所示:

[
    object,
    uuid(72A6E473-9956-4856-A335-B9169359AACE),
    dual,
    nonextensible,
    pointer_default(unique)
]
interface IA : IDispatch
{
    HRESULT MethodA();
}

[
    object,
    uuid(378846D3-7E24-4DAE-B4DF-69AA4B0C1AA9),
    dual,
    nonextensible,
    pointer_default(unique)
]
interface IB : IA
{
    HRESULT MethodB();
}

[
    object,
    uuid(4C187526-6809-4A57-A3ED-626E0B36F7DB),
    dual,
    nonextensible,
    pointer_default(unique)
]
interface ICollection : IDispatch
{
    HRESULT GetObject([out, retval] IA** ppValue);
}

ICollection 实现将返回一个实现 IB 的对象。该对象将通过调度接口提供对 MethodA 和 MethodB 的访问。运行时不会添加其他成员。

在这种情况下是否允许 IA 上的不可扩展属性?

4

1 回答 1

1

在这种情况下是否允许 IA 上的不可扩展属性?

是的。

接口的[nonextensible]属性,翻译成 typelib 类型标志TYPEFLAG_FNONEXTENSIBLE,具有告诉 Visual Basic(6 或应用程序)不要寻找缺少的成员的实际效果IDispatch

Dim A As IA
Set A = Obj ' QueryInterface
A.MethodA
' Compilation error
' A.MethodB
' If A.Property Then A.MethodC

Dim B As IB
Set B = Obj ' QueryInterface
B.MethodA
B.MethodB
' Compilation error
' If B.Property Then B.MethodC

如果没有[nonextensible],Visual Basic 会将缺少的方法调用和属性访问(如果未注释)编译为对IDispatch::GetIDsOfNames后跟IDispatch::Invoke.

Object通常,如果您喜欢编译时检查,强制代码将变量声明为或者Variant如果它需要动态查找,这是一件好事。对 expando 对象可能会很麻烦,但无论如何这些都违反了IDispatch' 合同的一点:

IDispatch::GetIDsOfNames 方法
...<br /> 备注
...<br /> 成员和参数 DISPIDs 必须在对象的生命周期内保持不变。这允许客户端一次获取 DISPID,并缓存它们以供以后使用。
…<br /> 注意 您不能使用此方法访问已动态添加的值,例如通过 JavaScript 添加的值。而是使用 IDispatchEx 接口的 GetDispID。有关详细信息,请参阅IDispatchEx 接口
…<br />


编辑:这是您可以尝试使用 Word VBA ( Alt+ F11) 的示例,添加一个宏并粘贴此文本:

Dim Docs As Documents
Set Docs = Application.Documents
Docs.Add
' Compilation error
' Docs.Foo
Dim Doc As Document
Set Doc = Docs(0)
Doc.Activate
Doc.Foo

要试用它,请选择菜单 Debug → Compile Project。

它应该编译成功。尽管(默认)接口(for)Document没有Foo方法,但它没有[nonextensible](小心双重否定),因此调用变成了运行时调度。

现在,取消注释Docs.Foo并重新编译项目。

它应该抛出一个错误,因为(默认)接口(for)Documents[nonextensible]并且对丢失Foo方法的调用不会变成运行时调度。

于 2014-07-11T00:56:02.927 回答