Why does iterating a Hashtable with `For Each` not work in VBScript?(为什么在 VBScript 中使用“For Each迭代 Hashtable 不起作用?)
问题描述
为什么可以使用 For Each 而不是 Hashtable 来迭代 ArrayList?
Dim iFor Each i In CreateObject("System.Collections.ArrayList") ' 没有错误下一个For Each i In CreateObject("System.Collections.Hashtable") ' 错误下一个迭代 HashTable 得到 p><块引用>
对象不支持此属性或方法.
脚本语言有一个技术限制,它们只能使用coclass的默认接口.他们根本没有接口的概念,也没有通过 IUnknown::QueryInterface() 获取另一个接口的后门.就像您可以在 C# 中通过转换为所需的接口类型一样.ArrayList 的迭代器如下所示:
私有密封类 ArrayListEnumeratorSimple : IEnumerator, ICloneable {//等等...}IEnumerator 是默认界面,您可以在 VBScript 中使用它.但是,Hashtable 的枚举器看起来像这样:
私有类 HashtableEnumerator : IDictionaryEnumerator, IEnumerable, ICloneable {//等等..}IDictionaryEnumerator 是默认值,而不是 IEnumerable.因此 VBScript 找不到所需的 Current 和 MoveNext 成员.只有Entry、Key和Value,它们是无用的.Keys and Values 集合也差不多:
公共类 KeysCollection : ICollection, IEnumerable {//等等..}同样的问题,CopyTo、Count、IsSynchronized 和 SyncRoot 都没用.通过将 [ComDefaultInterface] 属性应用于这些类,Microsoft 可以很容易地解决此问题.但他们没有.
<小时>这可以解决.需要的是可以 QI 默认接口以获得 IEnumerable 接口的代码.你可以帮助一个小的 C# 类库项目:
使用系统;使用 System.Collections;使用 System.Runtime.InteropServices;命名空间 VBScript{[ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]公共接口 IMapper {IEnumerable ToEnum(object itf);}[ComVisible(true), ProgId("VBScript.Mapper")]公共类映射器:IMapper {公共 IEnumerable ToEnum(对象 itf){返回(IEnumerable)itf;}}}使用 32 位和 64 位版本的 Regasm 构建和注册程序集.现在你可以让这个脚本工作了:
设置表 = CreateObject("System.Collections.Hashtable")table.Add 1, "一"table.Add 2, "两个"设置映射器 = CreateObject("VBScript.Mapper")对于 mapper.ToEnum(table.Keys) 中的每个键WScript.Echo 键 &":" &表(键)下一个输出:
Microsoft (R) Windows Script Host 版本 5.812版权所有 (C) 微软公司.版权所有.1:一个2:两个Why can one iterate an ArrayList using For Each but not a Hashtable?
Dim i
For Each i In CreateObject("System.Collections.ArrayList") ' no error
Next
For Each i In CreateObject("System.Collections.Hashtable") ' error
Next
Iterating the HashTable gives
Object doesn't support this property or method.
Scripting languages have a technical limitation, they can only use the default interface of a coclass. They have no notion of interfaces at all and no back-door to obtain another interface through IUnknown::QueryInterface(). Like you can in C# by casting to the desired interface type. The iterator for ArrayList looks like this:
private sealed class ArrayListEnumeratorSimple : IEnumerator, ICloneable {
// etc...
}
IEnumerator is the default interface, you have no problem using it from your VBScript. However, the enumerator for Hashtable looks like this:
private class HashtableEnumerator : IDictionaryEnumerator, IEnumerable, ICloneable {
// etc..
}
IDictionaryEnumerator is the default, not IEnumerable. So VBScript cannot find the required Current and MoveNext members. Only Entry, Key and Value, they are useless. Much the same for the Keys and Values collection:
public class KeysCollection : ICollection, IEnumerable {
// etc..
}
Same problem, CopyTo, Count, IsSynchronized and SyncRoot are useless. Microsoft could have very easily fixed this problem by applying the [ComDefaultInterface] attribute to these classes. But they didn't.
This can be worked around. What is required is code that can QI the default interface to obtain the IEnumerable interface. You can help with a wee C# class library project:
using System;
using System.Collections;
using System.Runtime.InteropServices;
namespace VBScript
{
[ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IMapper {
IEnumerable ToEnum(object itf);
}
[ComVisible(true), ProgId("VBScript.Mapper")]
public class Mapper : IMapper {
public IEnumerable ToEnum(object itf) {
return (IEnumerable)itf;
}
}
}
Build and register the assembly with both the 32-bit and 64-bit version of Regasm. Now you can make this script work:
Set table = CreateObject("System.Collections.Hashtable")
table.Add 1, "one"
table.Add 2, "two"
Set mapper = CreateObject("VBScript.Mapper")
For Each key in mapper.ToEnum(table.Keys)
WScript.Echo key & ": " & table(key)
Next
Output:
Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.
1: one
2: two
这篇关于为什么在 VBScript 中使用“For Each"迭代 Hashtable 不起作用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:为什么在 VBScript 中使用“For Each"迭代 Hashtable 不起作用?
基础教程推荐
- 是否可以在 asp classic 和 asp.net 之间共享会话状态 2022-01-01
- 全局 ASAX - 获取服务器名称 2022-01-01
- 错误“此流不支持搜索操作"在 C# 中 2022-01-01
- 将事件 TextChanged 分配给表单中的所有文本框 2022-01-01
- 经典 Asp 中的 ResolveUrl/Url.Content 等效项 2022-01-01
- 从 VS 2017 .NET Core 项目的发布目录中排除文件 2022-01-01
- 如何动态获取文本框中datagridview列的总和 2022-01-01
- 首先创建代码,多对多,关联表中的附加字段 2022-01-01
- 在 VS2010 中的 Post Build 事件中将 bin 文件复制到物 2022-01-01
- JSON.NET 中基于属性的类型解析 2022-01-01
