从字符串计算嵌套属性调用

本文关键字:属性 调用 嵌套 计算 字符串 | 更新日期: 2023-09-27 18:28:44

我目前正在阅读《500行或更少》一书,这是关于从Ned Batchelder创建模板引擎的章节。

他们的例子是使用Python。在他们的模板引擎中,他们将代码构建为字符串,然后调用exec(docs)将字符串计算为Python代码。

def get_globals(self):
    """Execute the code, and return a dict of globals it defines."""
    # A check that the caller really finished all the blocks they started.
    assert self.indent_level == 0
    # Get the Python source as a single string.
    python_source = str(self)
    # Execute the source, defining globals, and return them.
    global_namespace = {}
    exec(python_source, global_namespace)
    return global_namespace

这非常方便,因为他们可以很容易地评估模板中的表达式,如{{object.property.property}}

有了C#作为我的主要编程语言,我想知道如何实现这一点(在书中构建模板引擎的背景下)?

研究和思考

首先,我不相信C#中有exec等价物。

我可以想到的一种方法是递归地使用反射来获取对象的属性列表(处理空引用的检查),但从性能的角度来看,我不喜欢这样。

另一种方法是使用Roslyn的ScriptEngine类(我还没有使用过,所以如果我错了,请纠正我)。但我担心这不太好,因为这应该是一个库,不能与旧版本的C#和.NET一起使用。示例

从字符串计算嵌套属性调用

Q: 首先,我不相信C#中有一个exec等价物。

至于编译C#代码,CS-Script库可以通过各种方式来实现

例如:

dynamic script = CSScript.Evaluator
                         .LoadCode(@"using System;
                                     using Your.Custom.Relevant.Namespace;
                                     public class Executer
                                     {
                                         public object Execute()
                                         {
                                             return SomeStaticClass.array[123];
                                         }
                                     }");
int result = script.Execute();
//shorter way
int a = (int)CSScript.Evaluator.Evaluate("some.namespace.SomeStaticClass.array[123]");

点击此处阅读更多信息:http://www.csscript.net/

CS-Script不是为模板化而设计的
除非您在编译字符串之前通过操纵字符串自己创建它。

但是我如何为模板引擎传递一些上下文

您可以将上下文传递到如下函数中:

dynamic script = CSScript.Evaluator
                     .LoadCode(@"
                                using System;
                                using Namespace.Of.The.Context;
                                public class Executer {
                                    public string Execute(Context ctx) {
                                        return ctx.Person.Firstname + ctx.Person.Lastname;
                                    }
                                }");
int result = script.Execute(new Context(new Person("Rick", "Roll")));

Q: 我可以从普通的C#应用程序(比如Web应用程序)调用CSScript吗?

A: 是的

S-Script当前针对CLR(.NET)的Microsoft实现2.0/3.0/3.5/4.0/4.5),并完全支持Mono。

基本上,如果它运行C#,它可以根据库在其上执行的.net框架进行相应的编译,因此,如果您的项目在.net4.5上运行,则该.net版本的任何功能都可用,包括项目中的任何外部引用。

您可以使用Microsoft.CSharp.CSharpCodeProvider来实时编译代码。

https://msdn.microsoft.com/en-us/library/microsoft.csharp.csharpcodeprovider.aspx

像这样:

    static void Main(string[] args)
    {
        string source =
        @"
            namespace Test
            {
                public class Test
                {
                    public void HelloWorld()
                    {
                        System.Console.WriteLine(""Hello World"");
                    }
                }
            }
        ";
        var options = new Dictionary<string, string> {  {"CompilerVersion", "v3.5"} };
        var provider = new CSharpCodeProvider(options);
        var compilerParams = new CompilerParameters{GenerateInMemory = true,  GenerateExecutable = false };
        var results = provider.CompileAssemblyFromSource(compilerParams, source);
        var method = results.CompiledAssembly.CreateInstance("Test.Test");
        var methodInfo = method.GetType().GetMethod("HelloWorld");
        methodInfo.Invoke(method, null);
    }