2

好的,这是非常利基的,但我希望有人可以帮助我。另外,我对 CSharp 很熟悉,但对 JScript 和 COM 缺乏经验。

问题是这样的。我支持用 CSharp 编写并作为 COM 对象公开的应用程序组件。它公开了几个由其客户端应用程序调用的公共方法。客户端都是用 JScript 编写的经典 ASP 脚本文件。我想向返回对象集合的 COM 对象添加一个新的公共方法。

首先,返回单个结果对象工作正常......

我能够返回单个对象并访问它的属性。例如,在这个 C# 签名中......

ResultObject GetResult();

...ResultObject 是一个具有简单属性且没有逻辑的 POCO。我可以使用以下 JScript 访问它的属性:

var oMyObject = Server.CreateObject("MyNamespace.MyObject");
var result = oMyObject.GetResult();
Response.Write("<br /><i>('" + result.Value + "', '" + result.ID + "')</i>");

但是,当我返回一个数组时它会中断......

当我尝试从 C# 返回一个简单的 ResultObjects 数组时...

ResultObject[] GetResults();

...并从 JScript 访问它...

var oMyObject = Server.CreateObject("MyNamespace.MyObject");
var results = oMyObject.GetResults();
for (var i = 0; i < results.length; i++) {
    Response.Write("<br /><i>('" + results[i].Value + "', '" + results[i].ID + "')</i>");
}

...调用脚本时出现以下错误:

Microsoft JScript 运行时错误“800a138f”

'results.length' 为 null 或不是对象

此外,尝试 JScript“typeof results”会给我一种“未知”类型。

如何从作为 COM 对象公开的 CSharp 类返回集合(数组、IEnumerable 等)并从经典 ASP JScript 访问它?

4

2 回答 2

2

您可以做的是返回一个手工制作的集合,如下所示:

[ComVisible(true)] // may be optional depending on your other assembly settings
public class ResultList
{
    private List<Result> _innerList;

    internal ResultList(...parameters...)
    {
        _innerList = ...
    }

    public int Count
    {
        get
        {
            return _innerList.Count;
        }
    }

    public Result this[int index] // will be named "Item" in COM's world
    {
        get
        {
            return _innerList[index];
        }
    }
}

你可以这样使用:

var results = oMyObject.GetResults();
for (var i = 0; i < results.Count; i++) {
    Response.Write("<br /><i>('" + results.Item(i).Value + "', '" + results.Item(i).ID + "')</i>");
}
于 2013-08-13T14:34:33.983 回答
2

好吧,在问了这个问题之后,StackOverflow 提出了一些相关的问题,这些问题共同让我找到了解决方案。

This answer on a related question显示了我需要在 C# 中进行的更改。显然 COM 更喜欢使用它所谓的 SAFEARRAY。返回 SAFEARRAY 非常简单。我刚刚在 C# 中更改了我的方法的返回类型以返回一个“对象”,并添加了一个属性来指导 COM 如何编组返回值:

[return: MarshalAs(UnmanagedType.Struct, SafeArraySubType = VarEnum.VT_ARRAY)]
object GetResults();

然后,在从这个 C# 方法返回之前,我对我的数组进行了一些花哨的转换:

ResultObject[] retv = //create and populate the return value array
return retv.Cast<object>().ToArray();

这让我回到了返回 COM 友好的 SAFEARRAY 的地步。

(注意,“MarshalAs”属性似乎不是必需的。我的代码在没有它的情况下运行,但我喜欢它提供的关于返回值的澄清“文档”。)

然后这个答案显示了我需要在 JScript 中进行的更改。似乎 JScript 不能很好地与 SAFEARRAY 配合使用。幸运的是,您可以使用“toArray()”方法轻松地将其转换为 JScript 友好的数组:

var results = oMyObject.GetResults().toArray();

现在一切都按预期运行。

于 2013-08-13T16:44:42.107 回答