Skip to content

Commit a6e573d

Browse files
committed
update FAQ
1 parent 311f711 commit a6e573d

File tree

2 files changed

+202
-0
lines changed
  • src

2 files changed

+202
-0
lines changed

src/docs/faq/index.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,104 @@
22
title: "常见问题"
33
slug: "/常见问题"
44
---
5+
6+
<br/>
7+
8+
### 我想使用轻量级动态编译,听说 Natasha 预热要好几十 M 的内存,而且打包的大小也增加了,我感觉太重了。
9+
10+
答: Natasha 的预热是给萌新准备的,本意是忽略所有的准备工作直接进行动态编译。但是无论是 emit 还是 表达式树,都要反射相关的元数据给动态编译使用,如果你有 emit 和 表达式树 相关编程经验,就能知道你所编写的动态功能都依赖什么元数据了,而 Natasha 可以不预热并支持自定义添加元数据,参见以下示例, 该实例输入为 value, 输出为 Math.Floor(value/0.3):
11+
12+
#### emit 版本
13+
```cs
14+
DynamicMethod dynamicMethod = new DynamicMethod("FloorDivMethod", typeof(double), new Type[] { typeof(double) }, typeof(Program).Module);
15+
16+
ILGenerator ilGenerator = dynamicMethod.GetILGenerator();
17+
18+
ilGenerator.Emit(OpCodes.Ldarg_0);
19+
ilGenerator.Emit(OpCodes.Ldc_R8, 0.3);
20+
ilGenerator.Emit(OpCodes.Div);
21+
ilGenerator.Emit(OpCodes.Call, typeof(Math).GetMethod("Floor", new Type[] { typeof(double) }));
22+
ilGenerator.Emit(OpCodes.Ret);
23+
24+
Func<double, double> floorDivMethod = (Func<double, double>)dynamicMethod.CreateDelegate(typeof(Func<double, double>));
25+
```
26+
27+
#### 表达式树版本
28+
```cs
29+
ParameterExpression valueParameter = Expression.Parameter(typeof(double), "value");
30+
31+
Expression divisionExpression = Expression.Divide(valueParameter, Expression.Constant(0.3));
32+
Expression floorExpression = Expression.Call(typeof(Math), "Floor", null, divisionExpression);
33+
34+
Expression<Func<double, double>> expression = Expression.Lambda<Func<double, double>>(floorExpression, valueParameter);
35+
36+
Func<double, double> floorDivMethod = expression.Compile();
37+
```
38+
39+
#### Natasha 版本
40+
```cs
41+
AssemblyCSharpBuilder builder = new();
42+
var func = builder
43+
.UseRandomLoadContext()
44+
.UseSimpleMode()
45+
.ConfigLoadContext(ctx => ctx
46+
.AddReferenceAndUsingCode(typeof(Math))
47+
.AddReferenceAndUsingCode(typeof(double)))
48+
.Add("public static class A{ public static double Invoke(double value){ return Math.Floor(value/0.3); }}")
49+
.GetAssembly()
50+
.GetDelegateFromShortName<Func<double, double>>("A", "Invoke");
51+
```
52+
53+
#### Natasha 方法模板封装版
54+
> 该扩展库 `DotNetCore.Natasha.CSharp.Extension.MethodCreator` 在原 Natasha 基础上封装,并在 Natasha v9.0 版本后发布。
55+
```cs
56+
var simpleFunc = "return Math.Floor(arg1/0.3);"
57+
.WithSimpleBuilder()
58+
.WithMetadata(typeof(Math))
59+
.ToFunc<double, double>();
60+
```
61+
62+
以上两种 Natasha 的动态编译都不会引起几十M 的内存涨幅,属于按需构建。
63+
同时由此可以看出,无论哪种动态构建,都无法挣脱 `typeof(Math)` 的束缚,Natasha 同样支持轻量级的构建,甚至更加简洁。
64+
65+
### 我可以使用 Natasha 作为规则引擎吗?
66+
67+
答:Natasha 的动态构建能力非常强大,它是可以作为编写其他库的基础,这也是我当初开发此库的本意,你可以用 Natasha 封装属于你的规则引擎。
68+
69+
### 我不想每次都编译,能否缓存脚本的结果?
70+
71+
答:不可以,缓存结果需要您来完成,Natasha 走的是轻量化路线,`AssemblyCSharpBuilder` 为最小最基础的编译单元,如果你想缓存,可以自己实现一个 ConcurrentDictionary<string,Delegate/Action/Func> 来缓存结果。Natasha 不负责编译职责之外的事情。
72+
73+
### 我只想使用 using 全集,但不想添加那么多的引用。
74+
75+
答:Natasha 在 v9.0 版本后支持只预热 using 而不添加引用,新增了初始化方法:
76+
```cs
77+
NatashaManagement
78+
.GetInitializer()
79+
.WithMemoryUsing()
80+
//.WithRefUsing()
81+
//.WithMemoryReference()
82+
//.WithRefReference();
83+
//.WithExcludeReferences((asm, @namespace) =>
84+
//!string.IsNullOrWhiteSpace(@namespace) &&
85+
//@namespace.StartsWith("Microsoft.VisualBasic"))
86+
.Preheating<NatashaDomainCreator>();
87+
```
88+
### 能否复用之前创建的编译单元?
89+
90+
答:Natasha v9.0 之前不推荐复用,v9.0 后推出了 Api : `Reset`. 该方法有非常详细的注释引导和提示您需要注意的复用事项。
91+
92+
### 如果不懂元数据,也不想理 using 管理,能否写出一手好的可靠的动态功能逻辑?
93+
94+
答:很勉强,Natasha 全预热的情况下也不可避免复杂环境带来的各种版本不一致,using 滥用等情况。就拿简单的例子来说:
95+
```cs
96+
namspace MyNamespace{
97+
98+
public static class File{
99+
100+
}
101+
}
102+
```
103+
以上代码在 VS 开启隐式 using 情况下,也无法处理 File 在 System.IO 和 MyNamespace 之间引用不明的问题。
104+
而 Natasha 的 using 预热有时要比 VS 的 using 覆盖更加全面,因此出错的概率可能会更大。
105+
这需要编码规范来约束开发者,比如避开官方定义的类名,扩展类名等,比如使用 System.IO.File 避开命名空间引用冲突的问题。

src/i18n/zh-Hans/docusaurus-plugin-content-docs/current/faq/index.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,104 @@
22
title: "常见问题"
33
slug: "/常见问题"
44
---
5+
6+
<br/>
7+
8+
### 我想使用轻量级动态编译,听说 Natasha 预热要好几十 M 的内存,而且打包的大小也增加了,我感觉太重了。
9+
10+
答: Natasha 的预热是给萌新准备的,本意是忽略所有的准备工作直接进行动态编译。但是无论是 emit 还是 表达式树,都要反射相关的元数据给动态编译使用,如果你有 emit 和 表达式树 相关编程经验,就能知道你所编写的动态功能都依赖什么元数据了,而 Natasha 可以不预热并支持自定义添加元数据,参见以下示例, 该实例输入为 value, 输出为 Math.Floor(value/0.3):
11+
12+
#### emit 版本
13+
```cs
14+
DynamicMethod dynamicMethod = new DynamicMethod("FloorDivMethod", typeof(double), new Type[] { typeof(double) }, typeof(Program).Module);
15+
16+
ILGenerator ilGenerator = dynamicMethod.GetILGenerator();
17+
18+
ilGenerator.Emit(OpCodes.Ldarg_0);
19+
ilGenerator.Emit(OpCodes.Ldc_R8, 0.3);
20+
ilGenerator.Emit(OpCodes.Div);
21+
ilGenerator.Emit(OpCodes.Call, typeof(Math).GetMethod("Floor", new Type[] { typeof(double) }));
22+
ilGenerator.Emit(OpCodes.Ret);
23+
24+
Func<double, double> floorDivMethod = (Func<double, double>)dynamicMethod.CreateDelegate(typeof(Func<double, double>));
25+
```
26+
27+
#### 表达式树版本
28+
```cs
29+
ParameterExpression valueParameter = Expression.Parameter(typeof(double), "value");
30+
31+
Expression divisionExpression = Expression.Divide(valueParameter, Expression.Constant(0.3));
32+
Expression floorExpression = Expression.Call(typeof(Math), "Floor", null, divisionExpression);
33+
34+
Expression<Func<double, double>> expression = Expression.Lambda<Func<double, double>>(floorExpression, valueParameter);
35+
36+
Func<double, double> floorDivMethod = expression.Compile();
37+
```
38+
39+
#### Natasha 版本
40+
```cs
41+
AssemblyCSharpBuilder builder = new();
42+
var func = builder
43+
.UseRandomLoadContext()
44+
.UseSimpleMode()
45+
.ConfigLoadContext(ctx => ctx
46+
.AddReferenceAndUsingCode(typeof(Math))
47+
.AddReferenceAndUsingCode(typeof(double)))
48+
.Add("public static class A{ public static double Invoke(double value){ return Math.Floor(value/0.3); }}")
49+
.GetAssembly()
50+
.GetDelegateFromShortName<Func<double, double>>("A", "Invoke");
51+
```
52+
53+
#### Natasha 方法模板封装版
54+
> 该扩展库 `DotNetCore.Natasha.CSharp.Extension.MethodCreator` 在原 Natasha 基础上封装,并在 Natasha v9.0 版本后发布。
55+
```cs
56+
var simpleFunc = "return Math.Floor(arg1/0.3);"
57+
.WithSimpleBuilder()
58+
.WithMetadata(typeof(Math))
59+
.ToFunc<double, double>();
60+
```
61+
62+
以上两种 Natasha 的动态编译都不会引起几十M 的内存涨幅,属于按需构建。
63+
同时由此可以看出,无论哪种动态构建,都无法挣脱 `typeof(Math)` 的束缚,Natasha 同样支持轻量级的构建,甚至更加简洁。
64+
65+
### 我可以使用 Natasha 作为规则引擎吗?
66+
67+
答:Natasha 的动态构建能力非常强大,它是可以作为编写其他库的基础,这也是我当初开发此库的本意,你可以用 Natasha 封装属于你的规则引擎。
68+
69+
### 我不想每次都编译,能否缓存脚本的结果?
70+
71+
答:不可以,缓存结果需要您来完成,Natasha 走的是轻量化路线,`AssemblyCSharpBuilder` 为最小最基础的编译单元,如果你想缓存,可以自己实现一个 ConcurrentDictionary<string,Delegate/Action/Func> 来缓存结果。Natasha 不负责编译职责之外的事情。
72+
73+
### 我只想使用 using 全集,但不想添加那么多的引用。
74+
75+
答:Natasha 在 v9.0 版本后支持只预热 using 而不添加引用,新增了初始化方法:
76+
```cs
77+
NatashaManagement
78+
.GetInitializer()
79+
.WithMemoryUsing()
80+
//.WithRefUsing()
81+
//.WithMemoryReference()
82+
//.WithRefReference();
83+
//.WithExcludeReferences((asm, @namespace) =>
84+
//!string.IsNullOrWhiteSpace(@namespace) &&
85+
//@namespace.StartsWith("Microsoft.VisualBasic"))
86+
.Preheating<NatashaDomainCreator>();
87+
```
88+
### 能否复用之前创建的编译单元?
89+
90+
答:Natasha v9.0 之前不推荐复用,v9.0 后推出了 Api : `Reset`. 该方法有非常详细的注释引导和提示您需要注意的复用事项。
91+
92+
### 如果不懂元数据,也不想理 using 管理,能否写出一手好的可靠的动态功能逻辑?
93+
94+
答:很勉强,Natasha 全预热的情况下也不可避免复杂环境带来的各种版本不一致,using 滥用等情况。就拿简单的例子来说:
95+
```cs
96+
namspace MyNamespace{
97+
98+
public static class File{
99+
100+
}
101+
}
102+
```
103+
以上代码在 VS 开启隐式 using 情况下,也无法处理 File 在 System.IO 和 MyNamespace 之间引用不明的问题。
104+
而 Natasha 的 using 预热有时要比 VS 的 using 覆盖更加全面,因此出错的概率可能会更大。
105+
这需要编码规范来约束开发者,比如避开官方定义的类名,扩展类名等,比如使用 System.IO.File 避开命名空间引用冲突的问题。

0 commit comments

Comments
 (0)