オーバーロードとプライベートメソッドを持つJavaScriptオブジェクトから.NETタイプを継承します

はい、そうです、トリックはありません。 このアイデアは、約2か月前にアルゴリズムとソリューションに関する記事を熟考する過程で頭に浮かびました。 そのエンジンの.NETタイプは使いやすいですが、その逆も可能です...



エンジンについて少し
前回の記事では、機能については少なく、一般的なスクリプトから分離するのに役立つ可能性のあるものについて、より多くの記事を書いて、記事が自己宣伝のようにならないようにしました。 文字通り、最初のコメントから、私はこれが間違いであることに気づきました。

スピード

彼は速いです。 とても速い。 過去1か月にわたって、多くのコードがシャベルにかけられ、多くの特別なケースが整理され、結論が出されました。 たとえば、関数の記述方法と使用される言語ツールに応じて、インラインに相当するものから、各変数と引数のメモリの公平な割り当て、コンテキストの完全な初期化まで、10を超えるシナリオのいずれかで呼び出すことができます。

簡単な統合

プラットフォームの種類へのアクセスを提供するすべての重い「キッチン」は、1つの控えめな機能の背後に隠されています

JSObject TypeProxy.Proxy(object)
      
      





ほとんどすべてのオブジェクトを指定し、結果を変数に割り当てるだけです

 var script = new Script(" megaObject.alert('Hello from javascript') "); script.Context.DefineVariable("megaObject") .Assign(TypeProxy.Proxy(new { alert = new Action<string>(x => MessageBox.Show(x)) }); script.Invoke();
      
      





IListインターフェイスを実装する型には、そのようなオブジェクトをネイティブjs配列として偽装する特別なラッパーNiL.JS.Core.TypeProxing.NativeListがあります。

タイプコンストラクターを登録し、スクリプトの実行中に既にオブジェクトを作成できます。 タイプ名の変数が追加されます。

 script.Context.AttachModule(typeof(System.Windows.Forms.Form));
      
      





型を1つずつ追加するのが面倒な場合は、名前空間全体を追加できます

 Context.GlobalContext.DefineVariable ("forms") //  ,      . .Assign(new NamespaceProvider ("System.Windows.Forms")); //  ,     .
      
      





ただやっていない

各構文ツリーノードには、アセンブリの外部からアクセスできます。 仮想マシン、別の言語へのトランスレーター、静的アナライザー(十分な統合がない場合)、または想像力のある他の何かを実装できます。 すべての変数を使用するたびに、対応する記述子へのリンクが保存され、記述子に関する情報が得られます。 たとえば、最適化後に「生き残った」すべての使用場所を表示します。 そして数週間前、いわゆるVisitorが実装され、上記のすべてをさらに簡単に行うことができました。



一般的なスキーム



.NETプラットフォームで型を継承するには、型情報(メタデータ)が保存されているディスク上にあるアセンブリが必要です。 ただし、JSファイルはディスク上にありますが、タイプはありません。 これらは、このスクリプトのロジックが関数を実際に関数とコンストラクターに分割する実行時にのみ表示されます。 この問題の解決策はほとんどすぐに見つかりました-コンストラクター(「registerClass」)を取るグローバルコンテキストに関数を追加しました。 したがって、私は、いわば、メタデータを生成する価値があるjs関数を示すように頼みます。 ただし、これにはアイドル実行が必要です。

System.Reflection.Emitを使用して実行が完了すると、登録済みのコンストラクターごとに1つのクラスが宣言される保存済みアセンブリが作成されます。さらに、JavaScriptコードを格納し、初めてアクセスしたときに実行する静的なアセンブリーが作成されます。 この時点で、registerClass()の実行は既に使用されており、アセンブリ内の型とスクリプト内の型を一致させています。 すべてのラッパータイプは、相互作用の基本的なメカニズムを記述する1つのタイプから継承されます。 型の構成は、プロトタイプコンストラクターで見つかったものに基づいて形成されます。

 function ctor() { } ctor.prototype //       
      
      





したがって、プロトタイプに列挙不可能なプロパティを追加した場合、メタデータには該当せず、「プライベート」になります。



これで、JSオブジェクトを.NETオブジェクトとして作成できますが、約束された継承とオーバーロードはどこにありますか?!



これは簡単に決定されました。 どのメソッドがオーバーロードされているかを理解するために、ベース型のコンストラクターで、型のすべての関数を反復処理し(これは適切な場所ではないが、これはプロトタイプ実装には十分であると理解しています)、それらを宣言した型の祖先がチェックされます。 オーバーライドされたすべてのメソッドは、子孫型で宣言されます。 このようなチェックで検出できるすべてのメソッドは、JSタイプの実装に追加されます。 それだけです

これで、追加された新しい関数もjsで使用できるようになりますが、オーバーロードする必要はありません。



コードは大きくありません。GitHubで見ることができます



PSこのソリューションは、少なくともこの段階では、深刻な使用には適していません。 これは実験です。



All Articles