Доступ к свойствам объектов JavaScript с использованием динамического типа в C # 4 - PullRequest
7 голосов
/ 11 марта 2011

Я определяю com-объект как динамический тип в c #. Я могу вызывать методы довольно легко.Однако, когда я пытаюсь получить доступ к свойству того же объекта, я получаю недопустимое исключение приведения.

Рассматриваемый объект - это массив, переданный в управляемый код из JavaScript, и я хочу получить его свойство lengthкак int.

Я знаю, что мне не хватает чего-то странного, потому что я не получаю исключение «не содержит определения», и я могу легко получить доступ к свойству, используя отражение / InvokeMember.

Почемуя не могу преобразовать свойство длины динамического типа в целое число?

Например

Это терпит неудачу

   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, используя тип dynamic.(т.е. первый пример здесь, который терпит неудачу, фактически работает).Однако, если это многомерный массив, такой как следующая структура в JavaScript.

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

Тогда я получаю сообщение об ошибке при попытке динамического доступа к его свойству длины.Обратите внимание, что я все еще могу получить доступ к длине через отражение в этом случае.Мне кажется, что по какой-то причине свойство length не отображается правильно, когда многомерный массив используется в качестве dynmaic типа ...

В моем случае, что я сделал, чтобы решить (!?) этодобавьте свойство 'length_' в массив следующим образом, прежде чем передавать его.

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

Теперь в управляемом коде я могу получить доступ к этому свойству, как и ожидалось, без ошибок.Далеко от идеала, но, кажется, работает ...

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

Дальнейшее обновление

Хорошо, так что кажется, что, как и свойство length, индекс объектов теряетсяк динамическому типу, а также.Опять же, это доступно через отражение, хотя ...

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

Работает

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

1 Ответ

3 голосов
/ 16 марта 2011

Проще говоря, вы не можете получить доступ к свойству длины многомерного массива в c # через динамический тип, если, кажется, вы сначала не использовали свойство длины в JavaScript ...

Простой тест, приведенный ниже, показывает это очень четко.Я надеюсь, что это спасет кого-то еще от царапин на голове, которые у меня были в течение последнего дня или около того.

[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 на компьютере).Я могу только предположить, что движок JavaScript IE9 'Chakra' делает в этом случае что-то дополнительное / отличное от старого движка js.

...