# Leo
**Repository Path**: Maple-512/Leo
## Basic Information
- **Project Name**: Leo
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2021-07-30
- **Last Updated**: 2021-07-30
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
中文 |
English
# Leo
一个高性能的类型动态操作库。
[](https://github.com/night-moon-studio)
[](https://www.nuget.org/packages/NMS.NCaller)

[](https://996.icu/#/zh_CN)
[](https://github.com/night-moon-studio/NCaller/blob/master/LICENSE)
本项目基于 [NCC Natasha](https://github.com/dotnetcore/natasha) 和 .NET。
通过运行时自动构建高性能操作代理类。为普通类、静态类、动态类、嵌套动态类以及动态生成的静态类等提供了完备的高性能操作。
成员索引及类型缓存均采用高性能算法进行重建。如果反射、Dynamic 等方法都不能满足你的特殊需求,则你可以选择使用本方案。
### 持续构建
| CI Platform | Build Server | Master Test |
|--------- |------------- | --------|
| Github |  | [](https://github.com/night-moon-studio/tree/actions) |
## 开始
### 安装
Leo 可通过以下命令安装在你的项目中
```shell
PM> Install-Package NMS.Leo
PM> Install-Package NMS.Leo.Typed
```
### Natasha 初始化
```C#
// 仅仅注册组件
NatashaInitializer.Initialize();
// 或者
// 注册组件+预热组件 , 之后编译会更加快速
await NatashaInitializer.InitializeAndPreheating();
```
### 核心用法
Leo 使用了 NCC BTFindTree Algorithm 作为方法查找算法,并默认选用 `Precision`(精确最小权)来构建属性和字段的索引。
#### 创建字典操作器
使用精确最小权方法构建属性和字段索引:
```c#
var handler = PrecisionDictOperator.CreateFromType(typeof(A));
// or
var handler = PrecisionDictOperator.Create();
```
使用哈希二分查找方法构建属性和字段索引:
```c#
var handler = HashDictOperator.CreateFromType(typeof(A));
// or
var handler = HashDictOperator.Create();
```
使用模糊指针查找方法构建属性和字段索引:
```c#
var handler = FuzzyDictOperator.CreateFromType(typeof(A));
// or
var handler = FuzzyDictOperator.Create();
```
#### 字典操作器的调用
假设有两个类型 A 和 B:
```c#
public class A
{
public int Age;
public DateTime Time;
public B Outter = new B();
}
public class B
{
public string Name;
public B()
{
Name = "小明"
}
}
```
则我们可以如此调用字典操作器:
```c#
var handler = PrecisionDictOperator.CreateFromType(typeof(A));
handler.New();
handler["Age"]= 100; // Set operation
handler.Set("Age", 100); // Set operation
Console.WriteLine(handler["Time"]); // Get operation
Console.WriteLine(handler.Get("Time")); // Get operation
((B)handler["Outter"]).Name = "NewName"; // Link operation
```
### 动态构建类型
我们首先准备一段文本:
```c#
string text = @"
using System;
using System.Collections;
using System.Linq;
using System.Text;
namespace HelloWorld
{
public class Test
{
public Test(){
Name=""111"";
Pp = 10;
Rp=""aa"";
}
private long Pp;
private readonly string Rp;
public string Name;
public int Age{get;set;}
}
}";
```
然后通过 Natasha 构建运行时类型:
```c#
var oop = new AssemblyCSharpBuilder();
oop.Add(text);
Type type = oop.GetTypeFromShortName("Test");
```
最后使用 Leo 来操作这个运行时类型的实例:
```c#
var instance = PrecisionDictOperator.CreateFromType(type);
// 如果使用 NMS.Leo.Typed 的 LeoVisitor,则这两部是自动完成的
var obj = Activator.CreateInstance(type);
instance.SetObjInstance(obj);
instance["Pp"] = 30L;
instance["Rp"] = "ab";
instance.Set("Name", "222");
```
## Leo Visitor
在 `NMS.Leo.Typed` 包中提供了更易使用的封装。
引用命名空间:
```c#
using NMS.Leo.Typed;
```
### 创建 Visitor 实例
Leo Visitor 支持通过类型(Type)和泛型来创建:
```c#
var type = typeof(YourType);
var visitor = LeoVisitorFactory.Create(type); // returns ILeoVisitor instance
// or
var visitor = LeoVisitorFactory.Create(); // returns ILeoVisitor instance
```
### 设置或获取实例对象
你可以为 Leo Visitor 给定一个已存在的对象:
```c#
var type = typeof(YourType);
var instance = new YourType();
// 直接在工厂方法中给定实例对象:
var visitor = LeoVisitorFactory.Create(type, instance); // returns ILeoVisitor instance
// or
var visitor = LeoVisitorFactory.Create(instance); // returns ILeoVisitor instance
```
然后从 Leo Visitor 中获取实例对象:
```c#
object instance = visitor.Instance; // 从 ILeoVisitor 中获得 object 对象。
// or
T instance = visitor.Instance; // 从 ILeoVisitor 中获得类型 T 的实例。
```
### 使用字典初始化 Leo Visitor
在创建 Leo Visitor 时,也可以使用字典直接初始化实例:
```c#
var d = new Dictionary();
d["Name"] = "YourMidName";
d["Age"] = 25;
var type = typeof(YourType);
var visitor = LeoVisitorFactory.Create(type, d); // returns ILeoVisitor
// or
var visitor = LeoVisitorFactory.Create(d); // returns ILeoVisitor
```
然后从 Leo Visitor 中获取实例对象:
```c#
object instance = visitor.Instance; // 从 ILeoVisitor 中获得 object 对象。
// or
T instance = visitor.Instance; // 从 ILeoVisitor 中获得类型 T 的实例。
```
### 设置或获取值
可以通过 `GetValue` 或 `SetValue` 方法读写 Leo Visitor 中的值。
#### GetValue
从 Leo Visitor 中读取名为 `Name` 的字段或属性的值:
```c#
var visitor = LeoVisitorFactory.Create(typeof(YourType)); // ILeoVisitor
object name = visitor.GetValue("Name");
// or
string name = visitor.GetValue("Name");
// or
object name = visitor["Name"];
// or
object name = visitor.GetValue(t => t.Name);
// or
string name = visitor.GetValue(t => t.Name);
// or
string name = visitor.GetValue(t => t.Name); // 仅支持 ILeoVisitor
```
或者通过字典一次获得所有字段或属性的值:
```c#
var d = visitor.ToDictionary(); // Dictionary
```
#### SetValue
将值 `YourName` 设置给名为 `Name` 的字段或属性:
```c#
var visitor = LeoVisitorFactory.Create(typeof(YourType)); // ILeoVisitor
visitor.SetValue("Name", "YourName");
// or
visitor["Name"] = "YourName";
// or
visitor.SetValue(t => t.Name, "YourName");
// or
visitor.SetValue(t => t.Name, "YourName");
// or
visitor.SetValue(t => t.Name, "YourName"); // 仅支持 ILeoVisitor
```
甚至可以通过字典直接批量操作:
```c#
var d = new Dictionary();
d["Name"] = "YourMidName";
d["Age"] = 25;
visitor.SetValue(d);
```
### 选择需要返回的成员
我们可以通过 `Select` 来选择并返回我们需要的成员:
```c#
var visitor = LeoVisitorFactory.Create(typeof(YourType)); // ILeoVisitor
var z0 = v.Select((name, val) => name); // returns ILeoSelector
var z1 = v.Select((name, val, metadata) => name); // returns ILeoSelector
var z2 = v.Select(ctx => ctx.Name); // returns ILeoSelector
var z3 = v.Select(ctx => (ctx.Name, ctx.Index)); // returns ILeoSelector
var z4 = v.Select(ctx => new {ctx.Name, ctx.Value, ctx.Index}); // returns ILeoSelector
```
此时我们会获得一个 ILeoSelector 接口的实现,我们只需要执行 `FireAndReturn()` 方法便可获得我们所需要的结果:
```c#
var l0 = z0.FireAndReturn(); // returns IEnumerable
var l1 = z1.FireAndReturn(); // returns IEnumerable
var l2 = z2.FireAndReturn(); // returns IEnumerable
var l3 = z3.FireAndReturn(); // returns IEnumerable<(Name, Index)>
var l4 = z4.FireAndReturn(); // returns IEnumerable<{Name, Value, Index}>
```
## Leo Getter 与 Setter
我们可以通过内置的 `LeoGetter` 和 `LeoSetter` 流畅地创建实例或值的读取器(Getter)或设置器(Setter)。
### 实例读取器:`ILeoGetter`
我们可以通过实例读取器(对外暴露 `ILeoGetter`)从实例中获取其成员(属性或字段)的值。
```c#
var type = typeof(YourType);
var act = new YourType()
{
Name = "YourName",
Age = 22,
Country = Country.China,
Birthday = DateTime.Today
};
var getter = LeoGetter.Type(type).Instance(act); // returns ILeoGetter
// or
var getter = LeoGetter.Type().Instance(act); // return ILeoGetter
```
在创建实例读取器时,我们可以通过字典进行初始化,此时,实例读取器将自行构建一个对象。
```c#
var d = new Dictionary();
d["Name"] = "YourName";
var getter = LeoGetter.Type(type).InitialValues(d); // returns ILeoGetter
```
然后,我们可以读取实例内的值:
```c#
var val = getter.GetValue("Name");
```
本质上讲,实例读取器是一个只读的 `ILeoVisitor`。
### 实例设置器:`ILeoSetter`
我们可以通过内置的实例设置器(对外暴露 `ILeoSetter`)向实例的成员(属性或字段)设置值。
```c#
var type = typeof(YourType);
```
可以将实例直接传入实例设置器:
```c#
var act = new YourType()
{
Name = "YourName",
Age = 22,
Country = Country.China,
Birthday = DateTime.Today
};
var setter = LeoSetter.Type(type).Instance(act); // ILeoSetter
// or
var setter = LeoSetter.Type().Instance(act); // ILeoSetter
```
或使用字典:
```c#
var d = new Dictionary();
d["Name"] = "YourName";
var setter = LeoSetter.Type(type).InitialValues(d); // ILeoSetter
```
或使用全新的对象:
```c#
var setter = LeoSetter.Type(type).NewInstance(); // ILeoSetter
// or
var setter = LeoSetter.Type().NewInstance(); // ILeoSetter
```
然后,我们就可以设置实例内的值:
```c#
setter.SetValue("Name", "YourMidName");
```
本质上讲,实例设置器是一个只写的 `ILeoVisitor`。
### 值读取器:`ILeoValueGetter`
通过值读取器,我们可以在较细的颗粒度下对实例内某个成员(属性或字段)进行读取,值读取器可以避免使用者读取到无关成员(属性或字段)的值。
```c#
var type = typeof(YourType);
var fluentGetter = LeoGetter.Type(type).Value("Name"); // returns IFluentValueGetter
// or
var fluentGetter = LeoGetter.Type().Value("Name"); // returns IFluentValueGetter
// or
var fluentGetter = LeoGetter.Type().Value(t => t.Name); // returns IFluentValueGetter
// or
var fluentGetter = LeoGetter.Type().Value(t => t.Name); // returns IFluentValueGetter
```
随后,我们为 `fluentGetter` 指定具体的实例:
```c#
var act = new YourType()
{
Name = "YourName",
Age = 22,
Country = Country.China,
Birthday = DateTime.Today
};
var getter = fluentGetter.Instance(act); // ILeoValueGetter
```
最后,我们可以从实例里读取指定的成员(属性或字段):
```c#
var val = getter.Value;
```
### 值设置器:`ILeoValueSetter`
通过值设置器,我们可以在较细的颗粒度下对实例内某个成员(属性或字段)进行写入,值设置器可以避免使用者对无关成员(属性或字段)进行设置。
```c#
var type = typeof(YourType);
var fluentSetter = LeoSetter.Type(type).Value("Name"); // return IFluentValueSetter
// or
var fluentSetter = LeoSetter.Type().Value("Name"); // return IFluentValueSetter
// or
var fluentSetter = LeoSetter.Type().Value(t => t.Name); // return IFluentValueSetter
// or
var fluentSetter = LeoSetter.Type().Value(t => t.Name); // return IFluentValueSetter
```
随后,我们为 `fluentSetter` 指定具体的实例:
```c#
var act = new YourType()
{
Name = "YourName",
Age = 22,
Country = Country.China,
Birthday = DateTime.Today
};
var setter = fluentSetter.Instance(act); // ILeoValueSetter
```
最后,我们可以向实例的指定成员(属性或字段)设置值:
```c#
setter.Value("YourLastName");
```
## Leo 元数据
你可以从字典操作器中获得字段或属性的元数据:
```c#
var instance = PrecisionDictOperator.Create(); // DictBase
var members = instance.GetMembers(); // IEnumerable
// 或者只获得可读 / 可写的成员
var members = instance.GetCanReadMembers();
var members = instance.GetCanWriteMembers();
// 或者获取指定名称的属性或字段的元数据
var member = instance.GetMember("Name"); // LeoMember
```
你可以从 Leo Visitor 中获得字段或属性的元数据:
```c#
var visitor = LeoVisitorFactory.Create(typeof(YourType)); // ILeoVisitor
// 使用指定名称来获取对应的属性或字段的元数据
var member = visitor.GetMember("Name"); // LeoMember
// 或者直接指定该类型的成员来获取属性或字段的元数据
var member = visitor.GetMember( t => t.Name ); // 仅支持 ILeoVisitor
```
## 历史
- 2019-08-01 : 发布 v1.0.0.0, 高性能动态调用库。
- 2020-10-12 : 发布 v1.2.0.0, 使用最新版本 Natasha 与 [DynamicCache](https://github.com/night-moon-studio/DynamicCache) ,并使用函数指针代替系统委托。
## 算法
- NCC BTFindTree Algorithm: https://github.com/dotnet-lab/BTFindTree
## 性能

## 许可证
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fnight-moon-studio%2FNCaller?ref=badge_large)
[MIT](LICENSE)