评估来自字符串的嵌套 属性 调用
Evaluating nested property calls from a string
我目前正在阅读 Ned Batchelder 的“500 行或更少”book, the chapter 以创建模板引擎。
他们的示例使用 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
class(我没有用过,如果我错了请纠正我)。但我担心这不会很好,因为这应该是一个库,它不能与旧版本的 C# 和 .NET 一起使用。 Example
您可以使用 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);
}
Q: First I don't believe there is an exec equivalent in C#.
至于编译 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
不是 为模板制作的。
除非你在编译它们之前通过操作字符串来自己创建它。
But how can I pass some Context for the template engine
您可以像这样将上下文传递给函数:
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: Can I call CSScript from a normal C# application lets say a Web App?
A: Yes.
S-Script currently targets Microsoft implementation of CLR (.NET
2.0/3.0/3.5/4.0/4.5) with full support on Mono.
基本上,如果它运行 C#,它可以相应地编译到执行库的 .net-framework,所以如果你的项目是 运行 on .net4.5,任何功能该 .net 版本也可用,包括您项目中的任何外部引用。
我目前正在阅读 Ned Batchelder 的“500 行或更少”book, the chapter 以创建模板引擎。
他们的示例使用 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
class(我没有用过,如果我错了请纠正我)。但我担心这不会很好,因为这应该是一个库,它不能与旧版本的 C# 和 .NET 一起使用。 Example
您可以使用 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);
}
Q: First I don't believe there is an exec equivalent in C#.
至于编译 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
不是 为模板制作的。
除非你在编译它们之前通过操作字符串来自己创建它。
But how can I pass some Context for the template engine
您可以像这样将上下文传递给函数:
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: Can I call CSScript from a normal C# application lets say a Web App?
A: Yes.
S-Script currently targets Microsoft implementation of CLR (.NET 2.0/3.0/3.5/4.0/4.5) with full support on Mono.
基本上,如果它运行 C#,它可以相应地编译到执行库的 .net-framework,所以如果你的项目是 运行 on .net4.5,任何功能该 .net 版本也可用,包括您项目中的任何外部引用。