在C#4中使用动态类型访问JavaScript对象的属性

我在c#中将com对象定义为动态类型,我可以很容易地调用方法。 但是,当我尝试访问同一对象上的属性时,我得到一个无效的转换异常。

所讨论的对象是一个数组,通过JavaScript传递给托管代码,我希望将它的length属性作为int来获取。

我知道我错过了一些奇怪的东西,因为我没有得到'不包含定义'异常,我可以使用反射/ InvokeMember轻松访问属性。

为什么我不能将动态类型的长度属性转换为int?

例如

这失败了

   dynamic com = comObject;
   int i = com.length; // RTBE here.

这工作

   Type type = comObject.GetType();
   int i = (int)type.InvokeMember("length", BindingFlags.GetProperty, null, comObject, null);

*更新*

经过很多测试后,我已将这种奇怪缩小到多维数组的情况。 有问题的COM对象是从HTML文档传递到托管代码的参数。 对于所有意图和目的,对象有时在JavaScript中看起来像这样。

var x = ["a1", "a2", "a3"];

当像这样的数组来到托管代码时,我可以使用动态类型获得长度AOK。 (即这里的第一个例子实际上失败了)。 但是,如果它是一个多维数组,如JavaScript中的以下结构。

var y = [["b1", "b2", "b3"], "a2", "a3"];

然后,当试图动态地访问它的长度属性时,我得到一个错误。 请注意,在这种情况下,我仍然可以通过反射来查看长度。 在我看来,由于某些原因,当多维数组用作动态类型时,length属性不能正确映射......

在我的情况下,我已经做了什么来解决(!?)这是添加一个'length_'属性的数组像这样在传递之前。

var y = [["b1", "b2", "b3"], "a2", "a3"];
y.length_ = y.length;

现在在托管代码中,我可以按预期访问此属性而不会出错。 远非理想,但似乎工作...

   dynamic com = comObject;
   int i = com.length_; // 3!

进一步更新

好吧,看起来以及长度属性的对象索引也会丢失到动态类型。 虽然它可以通过反射来访问

失败

   dynamic com = comObject; // js array i.e. var x = [1, 2];
   int i = com[0]; // MissingMemberException - Error while invoking [PROPERTYGET, DISPID(0)].
   int i = com["0"]; // MissingMemberException - Error while invoking [PROPERTYGET, DISPID(0)].

作品

   Type type = comObject.GetType();
   int i = (int)type.InvokeMember("0", BindingFlags.GetProperty, null, comObject, null); // 1

简单地说,你不能通过动态类型访问c#中多维数组的长度属性,除非,看起来你已经在JavaScript中使用length属性了......

下面的简单测试很清楚地表明了这一点。 我希望这可以节省别人在最后一天左右的时间里头脑的搔痒。

[ComVisibleAttribute(true)]
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        webBrowser1.ObjectForScripting = this;

        StringBuilder html = new StringBuilder();
        html.Append("<script>");
        html.Append("var arr1 = [1, 2, 3, 4];");
        html.Append("var arr2 = [arr1, 2, 3, 4];");
        html.Append("var fn1 = function() { return arr1; };");
        html.Append("var fn2 = function() { return arr2; };");
        html.Append("var fn3 = function() { alert(arr2.length); }");
        html.Append("</script>");
        webBrowser1.DocumentText = html.ToString();

        webBrowser1.DocumentCompleted += (o, e) =>
        {
            dynamic arr1 = webBrowser1.Document.InvokeScript("fn1");
            int i = arr1.length;
            MessageBox.Show(i.ToString()); //4

            // If I call fn3 here then the arr2.length *is* available as int i2 below!
            ////webBrowser1.Document.InvokeScript("fn3"); // 4 

            dynamic arr2 = webBrowser1.Document.InvokeScript("fn2");
            int i2 = arr2.length;
            MessageBox.Show(i2.ToString()); // unless fn3 is called you get...
            /* 
            System.MissingMemberException was unhandled by user code
            Message=Error while invoking length.
            Source=System.Dynamic
            StackTrace:
            at System.Dynamic.ComRuntimeHelpers.CheckThrowException(Int32 hresult, ExcepInfo& excepInfo, UInt32 argErr, String message)
            at CallSite.Target(Closure , CallSite , ComObject )
            at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
            at CallSite.Target(Closure , CallSite , Object )
            at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
            */             
        };
    }
}

更新

看起来(请参阅注释)如果WebBrowser控件使用版本9的Internet Explorer(...该控件使用机器上的IE版本),则此行为已修复。 在这种情况下,我只能假定IE9'Chakra'JavaScript引擎正在做一些额外的/不同于旧的js引擎的东西。

链接地址: http://www.djcxy.com/p/5473.html

上一篇: Accessing properties of javascript objects using type dynamic in C# 4

下一篇: adding a custom command with the file name as a target