1

这是使用 IronRuby 的非常简单的表达式评估器的代码

public class BasicRubyExpressionEvaluator
{
    ScriptEngine engine;
    ScriptScope scope;
    public Exception LastException
    {
        get; set;
    }
    private static readonly Dictionary<string, ScriptSource> parserCache = new Dictionary<string, ScriptSource>();
    public BasicRubyExpressionEvaluator()
    {
        engine = Ruby.CreateEngine();
        scope = engine.CreateScope();

    }

    public object Evaluate(string expression, DataRow context)
    {
        ScriptSource source;
        parserCache.TryGetValue(expression, out source);
        if (source == null)
        {
            source = engine.CreateScriptSourceFromString(expression, SourceCodeKind.SingleStatement);
            parserCache.Add(expression, source);
        }

        var result = source.Execute(scope);
        return result;
    }
    public void SetVariable(string variableName, object value)
    {
        scope.SetVariable(variableName, value);
    }
}

这是问题。

var evaluator = new BasicRubyExpressionEvaluator();
evaluator.SetVariable("a", 10);
evaluator.SetVariable("b", 1 );
evaluator.Evaluate("a+b+2", null);

对比

var evaluator = new BasicRubyExpressionEvaluator();
evaluator.Evaluate("10+1+2", null);

第一个比第二个慢 25 倍。有什么建议么?String.Replace 对我来说不是解决方案。

4

2 回答 2

2

我不认为您看到的性能是由于变量设置造成的;无论您在做什么,程序中 IronRuby 的第一次执行总是比第二次慢,因为大多数编译器在代码实际运行之前不会加载(出于启动性能原因)。请再试一次该示例,也许循环运行每个版本的代码,您会发现性能大致相同;变量版本确实有一些方法调度的开销来获取变量,但如果你运行得足够多,那应该可以忽略不计。

此外,在您的托管代码中,您为什么要在字典中保留 ScriptScopes?我会保留 CompiledCode (engine.CreateScriptSourceFromString(...).Compile() 的结果)——因为这将在重复运行中帮助更多。

于 2009-12-15T08:33:41.587 回答
0

您当然可以首先构建字符串,例如

evaluator.Evaluate(string.format("a={0}; b={1}; a + b + 2", 10, 1))

或者你可以把它变成一种方法

如果您返回一个方法而不是您的脚本,那么您应该能够像使用常规 C# Func 对象一样使用它。

var script = @"

def self.addition(a, b)
  a + b + 2
end
"

engine.ExecuteScript(script);
var = func = scope.GetVariable<Func<object,object,object>>("addition");    
func(10,1)

这可能不是一个工作片段,但它显示了总体思路。

于 2009-11-05T08:45:09.620 回答