C#<->JScript: невидимый массив?

У меня есть немного сложная программа, которая дает мне эту, по-видимому, фантомную ошибку...
Я начну объяснять с помощью этого небольшого примера программы, которую я настроил, которая может бросить мое прекрасное исключение для всех, кто ее запускает.

<!-- language: c# -->
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace so_redux {
    static class Program {
        [STAThread]
        static void Main(){
            CS2JS _class=new CS2JS();
        }
    }//class Program

    class CS2JS{
        public CS2JS(){
            Func<String,Object> js_eval=initJS();
            Object cs_ic=initCS();

            string xc;
            object res;

            cs_ic.GetType().GetMethod("init").Invoke(cs_ic,null);
            AppDomain.CurrentDomain.SetData("trespasser",cs_ic);

            xc=@"function edata(fieldname:String,ival:String):Object{
                    var sob=System.AppDomain.CurrentDomain.GetData('trespasser');
                    var v1=sob.GetType().GetField(fieldname).GetValue(sob);

                    function HASH(s1:String,s2:String):Object{
                        var q1=sob.GetType().GetField(s1).GetValue(sob);
                        return q1.ITEM(s2);
                    }

                    var v2=v1.ITEM(ival);
                    return eval(v2);
                }
                edata('HT','foo');";
            res=js_eval(xc);
            // var xx;xx=new Hashtable();xx['sda']='1';eval(xx['sda']); OK            
        }

        Func<String,Object> initJS(){
            System.CodeDom.Compiler.CodeDomProvider jcc;
            System.CodeDom.Compiler.CompilerParameters jcp;
            System.CodeDom.Compiler.CompilerResults jcr;
            System.Reflection.Assembly jas;
            object jis;
            string code;
            Type t_ii;

            code=@"@set @debug(off)
                import System;
                import System.Collections;
                import System.Collections.Generic;
                package internal_namespace{class internal_class{
                    public function internal_method(_code:String):Object{
                        return eval(_code);
                    }
                }
            }";

            jcc=Microsoft.JScript.JScriptCodeProvider.CreateProvider("JScript");
            jcp=new System.CodeDom.Compiler.CompilerParameters();
            jcp.CompilerOptions="/fast-";
            jcp.GenerateExecutable=false;
            jcp.GenerateInMemory=true;
            jcp.IncludeDebugInformation=false;
            jcp.ReferencedAssemblies.Add("System.dll");
            jcp.ReferencedAssemblies.Add("System.Core.dll");
            jcp.WarningLevel=4;
            jcr=jcc.CompileAssemblyFromSource(jcp,code);
            jas=jcr.CompiledAssembly;
            jis=jas.CreateInstance("internal_namespace.internal_class");

            t_ii=jas.GetType("internal_namespace.internal_class");
            return (s1)=>t_ii.InvokeMember("internal_method",System.Reflection.BindingFlags.InvokeMethod,null,jis,new object[]{s1});
        }//initJS

        Object initCS(){
            var v1= Microsoft.CSharp.CSharpCodeProvider.CreateProvider("CSharp");
            System.CodeDom.Compiler.CompilerParameters v2=new System.CodeDom.Compiler.CompilerParameters();
            v2.GenerateExecutable=false;
            v2.GenerateInMemory=true;
            v2.IncludeDebugInformation=false;
            v2.WarningLevel=4;
            v2.ReferencedAssemblies.Add("System.dll");
            v2.ReferencedAssemblies.Add("System.Core.dll");

            string _code="public Hashtable2 HT;"+
                "public void init(){"+
                    "HT=new Hashtable2();"+
                    "HT[\"foo\"]=\"1\";"+
                    "HT[\"bar\"]=\"HASH('HT','foo')\";"+
                "}";

            var v3="using System;using System.Collections;using System.Collections.Generic;"+
                    "namespace internal_namespace{public class Hashtable2:Hashtable{"+
                        "public Hashtable2():base(){} public Hashtable2(int N):base(N){}"+
                        "public Object ITEM(Object K){return this[K];} }"+
                    "[Serializable]public class internal_class{"+
                        "public internal_class(){}"+
                        _code+
                        "\n}}";

            var v4=v1.CompileAssemblyFromSource(v2,v3);
            var v5=v4.CompiledAssembly;
            var v6=v5.GetType("internal_namespace.internal_class");
            var v7=v5.CreateInstance("internal_namespace.internal_class");

            return v7;
        }//initCS
    }//class CS2JS
}//namespace so_redux

Исключение, которое выдается, является "индексом за пределами" и генерируется из JScript. Эта проблема? Дело в том, что нет массива!

Что делает этот код: сначала инициализируется интерпретатор JScript путем компиляции во время выполнения класса, который "экспортирует" eval (можно было бы сделать dll, но в этом случае я этого не сделал).
Затем компилируется сборка C#, которая "экспортирует" некоторый пользовательский код (переменная _code в initCS изначально загружается путем чтения текстового файла).
После инициализации вновь скомпилированного класса (вызова init()) мне нужно, чтобы две сборки (JScript и C#) взаимодействовали, поэтому мне нужно передать данные между ними, и я подумал об использовании AppDomain.
Примечание: в сборке C# Hashtable2 определен, потому что я поместил туда метод ITEM, который можно использовать в качестве альтернативы общему свойству this[]: таким образом отладка проще (например, при показе святого MessageBox при доступе к значениям)).
Итак, я передаю класс, созданный в initCS, в JScript, и JScript читает внутреннюю Hashtable (HT). Что мне нужно сделать, это оценить данные в Hashtable, потому что он должен быть в состоянии динамически изменять себя.
Все работает нормально, если я получаю строку, не взятую из Hashtable, - в тот момент, когда я беру все, что находится в Hashtable, и передаю ее в eval, происходят исключения. Внимание: строки абсолютно одинаковы (даже сравнивая их с Equals) и они работают, разница только в том, откуда они берутся.
Когда функция JScript edata обнаруживает строку, взятую из Hashtable, JScript говорит "индекс за пределами", но, как я уже говорил, я не вижу там никакого массива... (и, возможно, проблема именно в этом, не знаю),
Я признаю, что у меня есть свои ограничения в JScript, поэтому, если кто-нибудь сможет помочь, чтобы понять, что происходит WTF, я был бы очень счастлив.

1 ответ

Временное решение / обходной путь, разделяющий функцию JScript:

    xc=@"function odata(fieldname:String,ival:String):Object{
            var sob=System.AppDomain.CurrentDomain.GetData('trespasser');
            var v1=sob.GetType().GetField(fieldname).GetValue(sob);

            return v1.ITEM(ival);
        }
        odata('HT','bar');";
    res=js_eval(xc);

    xc=@"function HASH(s1:String,s2:String):Object{
            var sob=System.AppDomain.CurrentDomain.GetData('trespasser');
            var q1=sob.GetType().GetField(s1).GetValue(sob);
            return q1.ITEM(s2);
        }
        eval("+res.ToString()+");";
    res=js_eval(xc);

но если кто-то действительно понял, почему это неправильно в первом примере, пожалуйста, объясните мне!

Другие вопросы по тегам