我有一個名爲EcmaEval的類,它允許我的應用程序用戶執行任意的javascript。這個課程的實施是在這個問題的最後。我允許用戶訪問一個「環境」對象,該對象提供的方法和屬性對他們來說是非常有用的。IDynamicMetaObjectProvider動態對象和JScript.Net
問題是我需要將C#動態對象暴露給JScript,但它不起作用。有沒有人做過這個 - 它應該工作嗎?
所以,如果我有一個普通的老對象與字符串屬性名爲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對象動態對象則不會(屬性名稱爲null):
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);
(結果爲null)
這裏的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);
}
}
}