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

发布于 2024-10-21 19:51:36 字数 1863 浏览 0 评论 0原文

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

有问题的对象是一个数组,从 JavaScript 传递到托管代码,我希望以 int 形式获取它的 length 属性。

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

为什么动态类型的length属性不能转换为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_”属性在传递数组之前就像这样。

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

I define a com object as a dynamic type in c# I am able to call methods quite easily.
However when I try to access a property on the same object I get an invalid cast exception.

The object in question is an array, passed to managed code from JavaScript, and I wish to get the length property of it as an int.

I know I am missing something odd because I am not getting a 'does not contain a definition' exception and I can access the property easily using reflection/InvokeMember.

Why can I not convert the length property of the dynamic type to an int?

For example

This Fails

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

This Works

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

* Update *

After a lot of testing I have narrowed this oddness to cases of multi-dimensional arrays.
The com object in question is a parameter passed from a html document to managed code. For all intents and purposes the object sometimes looks like this in JavaScript.

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

When an array like this comes to managed code I am able to get the length AOK using the type dynamic. (i.e. the first example here that fails actually works). However, if it is a multi-dimensional array such as the following structure in JavaScript.

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

Then I get an error when trying to access its length property dynamically. Note, I can still access the length via reflection in this case. It seems to me that for some reason the length property does not get correctly mapped when a multidimensional array is used as a dynmaic type...

In my case what I have done to solve(!?) this is add a 'length_' property to the array like so before passing it.

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

Now in managed code I can accesses this property as expected without error. Far from ideal but seems to work...

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

Further Update

Ok, so it seems that as well as the length property the objects index gets lost to the dynamic type as well. Again it is accessible via reflection though...

Fails

   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)].

Works

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一场春暖 2024-10-28 19:51:36

简单来说,您无法通过动态类型访问 C# 中多维数组的 length 属性,除非您似乎首先在 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 控件使用 Internet Explorer 版本 9(...该控件使用计算机上的 IE 版本),则此行为已修复。在这种情况下,我只能推测 IE9“Chakra”JavaScript 引擎正在做一些与旧 js 引擎不同的事情。

In simple terms you can't access the length property of a multi-dimensional array in c# via the type dynamic unless, it seems, you have used the length property in JavaScript first...

The simple test below shows this very clearly. I hope this saves someone else the head scratching I have been having over the last day or so.

[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)
            */             
        };
    }
}

update

It seems (see comments) that this behaviour is fixed if the WebBrowser control uses version 9 of Internet Explorer (...the control uses the version of IE on the machine). I can only presume that the IE9 'Chakra' JavaScript engine is doing something extra/different to the old js engine in this case.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文