代码之家  ›  专栏  ›  技术社区  ›  Daniel James Bryars

idynamicMetaObjectProvider动态对象和jscript.net

  •  1
  • Daniel James Bryars  · 技术社区  · 16 年前

    我有一个名为ecmaeval的类,它允许我的应用程序的用户执行任意的javascript。类的实现在这个问题的末尾。我允许用户访问“environment”对象,该对象提供方法和属性,这些方法和属性对用户编写脚本很有用。

    问题是我需要向JScript公开一个C动态对象,但它不起作用。以前有人做过这件事吗?这件事有用吗?

    所以,如果我有一个普通的旧对象,它有一个名为name的字符串属性,那么它会起作用:

            test test = new test();
            test.Name = "Daniel Bryars";
    
            EcmaEval ecmaEval = new EcmaEval(new List<String>
                                                 {
                                                     Assembly.GetExecutingAssembly().Location
                                                 }, test);
    
            String ecma = "environment.Name";
            String result = ecmaEval.Eval<String>(ecma);
    
            Assert.AreEqual("Daniel Bryars", result);
    

    但如果我将ecmaeval对象传递给一个动态对象,则它不会传递(属性名为空):

            dynamic expandoObject = new ExpandoObject();
            expandoObject.Name = "Daniel Bryars";
    
            EcmaEval ecmaEval = new EcmaEval(new List<String>
                                                 {
                                                     Assembly.GetExecutingAssembly().Location
                                                 }, expandoObject);
    
            String ecma = "environment.Name";
            String result = ecmaEval.Eval<String>(ecma);
                Assert.AreEqual("Daniel Bryars", result);
    

    (结果为空。)

    这是ecmaeval的实现。涉及到另一个名为jsObjectToDotNetConversion的类,它强制jsObjects成为c对象(它使用反射来创建c对象并设置字段和/或属性),但该类的实现并不相关。

    using System;
    using System.CodeDom.Compiler;
    using System.Collections.Generic;
    using System.Reflection;
    using Microsoft.JScript;
    
    namespace Aeriandi.ApplicationBlocks.BusinessBaseObjects.Ecma
    {
        /// <summary>
        /// Exposes the JScrip eval function as a .net method.
        /// This uses the "safe" JScript.Eval so no disk, or network access is allowed.
        /// </summary>
        public class EcmaEval
        {
            private readonly object _evaluator;
            private readonly Type _evaluatorType;
            private readonly Object _environment;
    
            public EcmaEval() : this (new List<string>(), null )
            {            
            }
    
            public EcmaEval(List<String> referencedAssemblies, Object environment)
            {
                if (null == referencedAssemblies)
                {
                    throw new ArgumentNullException("referencedAssemblies", "The argument referencedAssemblies must not be null");
                }
    
                _environment = environment;
                JScriptCodeProvider compiler = new JScriptCodeProvider();
    
                CompilerParameters parameters = new CompilerParameters();
                parameters.GenerateInMemory = true;
    
                foreach (String referencedAssembly in referencedAssemblies)
                {
                    parameters.ReferencedAssemblies.Add(referencedAssembly);
                }
    
                string _jscriptSource =
    @"package Evaluator
    {
        class Evaluator
        {
            public function Eval(expr : String, environment : Object) 
            { 
                return eval(expr); 
            }
        }
    }";
                CompilerResults results = compiler.CompileAssemblyFromSource(parameters, _jscriptSource);
    
                Assembly assembly = results.CompiledAssembly;
                _evaluatorType = assembly.GetType("Evaluator.Evaluator");
                _evaluator = Activator.CreateInstance(_evaluatorType);
            }
    
            public Object Eval(Type returnType, String ecmaScript)
            {
                ecmaScript = WrapInBrackets(ecmaScript);
    
                Object result = _evaluatorType.InvokeMember(
                         "Eval",
                         BindingFlags.InvokeMethod,
                         null,
                         _evaluator,
                         new object[] { ecmaScript, _environment }
                      );
    
                return JSObjectToDotNetConversion.Coerce(returnType, result);
            }
    
            public T Eval<T>(String ecmaScript)
            {
                return (T) Eval(typeof (T), ecmaScript);
            }
    
            private static String WrapInBrackets(String ecmaScript)
            {
                //You can't start a block of js with a { because it's ambiguous (according to the spec)
                //so we wrap everything in brackets.
                return String.Format("({0})", ecmaScript);
            }
        }
    }
    
    1 回复  |  直到 16 年前
        1
  •  0
  •   Daniel James Bryars    16 年前

    基本上,我不能用jscript.net来实现这一点。我想我需要使用一些构建在DLR上的东西,比如:

    艾伦斯

    http://github.com/fholm/IronJS

    托管JScript(不再由MS开发)

    http://www.microsoft.com/downloads/details.aspx?familyid=A5189BCB-EF81-4C12-9733-E294D13A58E6&displaylang=en

    还有一些关于托管JScript的更多信息,它将在这里消失: http://pietschsoft.com/post/2009/06/12/Managed-JScript-on-the-DLR-from-Microsoft-is-DEAD-Why.aspx