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