C#4のタイプダイナミックを使用したJavaScriptオブジェクトのプロパティへのアクセス

c#-4.0 dynamic properties reflection
C#4のタイプダイナミックを使用したJavaScriptオブジェクトのプロパティへのアクセス

C#でcomオブジェクトを動的型として定義し、メソッドを非常に簡単に呼び出すことができます。 ただし、同じオブジェクトのプロパティにアクセスしようとすると、無効なキャスト例外が発生します。

問題のオブジェクトは配列であり、JavaScriptからマネージコードに渡されます。その長さプロパティを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"];

このような配列がマネージコードになると、dynamic型を使用して長さ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

  7  1


ベストアンサー

簡単に言えば、JavaScriptで最初にlengthプロパティを使用していないように思われる場合を除き、動的タイプを介してc#の多次元配列のlengthプロパティにアクセスすることはできません…​

以下の簡単なテストは、これを非常に明確に示しています。 これにより、他の誰かが私が最後の日かそこらで持っていた頭の傷を救うことを願っています。

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

        StringBuilder html = new StringBuilder();
        html.Append("");
        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("");
        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エンジンとは何か特別なことをしていると推測できます。

3


タイトルとURLをコピーしました