对于熟悉JScript引擎实现的Eric Lippert或Microsoft的某个人来说,这确实是一个问题。
我可以这样做:
var obj = new ActiveXObject("My.ProgId");
var methods = GetMethodsViaMagic(obj);
(假设COM类型支持IDispatch)
如果是的话,GetMethodsViaMagic()
看起来像什么?
编辑 - 当然,我尝试的第一件事是for...in
循环,但这对ActiveX对象上定义的方法和属性不起作用。至少,不是我在.NET中定义并通过ComVisible
公开的对象。
在C#中,我可以像这样定义IDispatch:
[Guid("00020400-0000-0000-c000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDispatch
{
int GetTypeInfoCount();
System.Runtime.InteropServices.ComTypes.ITypeInfo
GetTypeInfo([MarshalAs(UnmanagedType.U4)] int iTInfo,
[MarshalAs(UnmanagedType.U4)] int lcid);
[PreserveSig]
int GetIDsOfNames(ref Guid riid,
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] rgsNames,
int cNames,
int lcid,
[MarshalAs(UnmanagedType.LPArray)] int[] rgDispId);
[PreserveSig]
int Invoke(int dispIdMember,
ref Guid riid,
[MarshalAs(UnmanagedType.U4)] int lcid,
[MarshalAs(UnmanagedType.U4)] int dwFlags,
ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams,
[Out, MarshalAs(UnmanagedType.LPArray)] object[] pVarResult,
ref System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo,
[Out, MarshalAs(UnmanagedType.LPArray)] IntPtr[] pArgErr);
}
然后我可以这样做:
var idispatch = (IDispatch) comObject ;
System.Runtime.InteropServices.ComTypes.ITypeInfo typeInfo =
idispatch.GetTypeInfo(0, 0);
System.Runtime.InteropServices.ComTypes.FUNCDESC funcDesc;
string strName, strDocString, strHelpFile;
int dwHelpContext;
typeInfo.GetFuncDesc(i, out pFuncDesc);// i = 1, 2, 3...
funcDesc = (System.Runtime.InteropServices.ComTypes.FUNCDESC)
Marshal.PtrToStructure(pFuncDesc,
typeof(System.Runtime.InteropServices.ComTypes.FUNCDESC));
...获取函数(方法)名称,参数数量等。
对于ActiveX(COM IDispatch)对象,我可以在JScript中执行类似的操作吗?
答案 0 :(得分:6)
首先,请记住,我已经十多年没有研究过JScript了。那段时间引擎发生了变化,我的记忆已经消失了。
最好的回忆和知识:如果对象实现了IDispatchEx,那么for-in循环将起作用,但如果对象只实现了IDispatch则不行。
我一直想添加一种机制,以便JScript程序可以使用与调度对象关联的类型信息中提供的信息来枚举属性,但我不相信我实际上已经编写过代码。
答案 1 :(得分:3)
我发现我可以使用Javascript for...in
循环来枚举方法和属性,如果我已经在ComVisible .NET对象上实现了IReflect 。
IReflect在整个CCW中被编组为IDispatch。
答案 2 :(得分:2)
你应该能够做到
var methods = [];
for( var property in obj ) {
if( obj.hasOwnProperty(property) && typeof obj[property] === 'function' ) {
methods.push(property);
}
}
methods
数组将包含方法名称。如果有问题的对象是某个构造函数的实例,您可能希望删除hasOwnProperty
检查,因为这会限制所有内容仅查看obj本身定义的属性/方法,而不是其原型链中的属性/方法
至于参数的数量,你可以使用(如评论中Domenic所指出的)the .length
property函数本身。
所以要在obj
中获取每个方法的名称和参数数量:
var methods = [];
for( var property in obj ) {
if( obj.hasOwnProperty(property) && typeof obj[property] === 'function' ) {
methods.push({
name: property,
args: obj[property].length
});
}
}
你将得到一个对象文字数组,每个对象文字包含来自obj
的方法的名称和参数个数。
编辑:当我第一次写这个答案时,我正在考虑获取名称(而不仅仅是数字)的参数,因此包含了一些相当hacky的代码来获取这些名称。万一有人感兴趣,这里是代码,我只是无耻地偷走改编自Prototype.js)
function argumentNames(func) {
var names = func.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
.replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
.replace(/\s+/g, '').split(',');
return names.length == 1 && !names[0] ? [] : names;
}
将一个函数/方法传递给该函数,它会返回参数名称...... 也许。如果您获得的对象是完全成熟的主机对象,则toString()
可能无法读取其方法/函数。通常,toString()
将返回方法/函数的实际源代码(并且argumentNames
函数用一些正则表达式解析),但在本机代码的情况下,您可能只是获取字符串“native代码“或其他东西,而不是源代码。