Natasha 高级编译类 - 第一部分

Posted 摧残一生 涅槃重生

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Natasha 高级编译类 - 第一部分相关的知识,希望对你有一定的参考价值。

模板类的使用,类似于Lambda

类名 作用 命名空间 操作类型
NAssembly 快速创建同程序集的 oop 及委托等操作类 全局 静态初始化,动态实例化
NInstance 根据类型,提供一个初始化实例的委托 全局 静态
NDelegate 快速创建指定域的 Action/Func 委托 全局 静态初始化,动态实例化
NClass 快速创建一个公有类 全局 静态初始化,动态实例化
NInterface 快速创建一个公有接口 全局 静态初始化,动态实例化
NEnum 快速创建一个枚举类 全局 静态初始化,动态实例化
NRecord 快速创建一个记录类 全局 静态初始化,动态实例化
NStruct 快速创建一个结构体 全局 静态初始化,动态实例化
FakeMethodOperator 仿造 MethodInfo 创建方法 Natasha.CSharp 静态初始化,动态实例化
FastMethodOperator 快速创建方法 Natasha.CSharp 静态初始化,动态实例化

NClass

感觉该类的使用频率会比较高

注意:NClass可以通过获得Method后在进行方法调用,或者实例化以后

使用自带方法进行创建

NatashaManagement.Preheating();
using (NatashaManagement.CreateDomain("Test").CreateScope())
    // 创建class
    NClass builder = NClass.UseScope();
    var type = builder
        // 不包含全局using
        .NoGlobalUsing()
        // 隐藏命名空间
        .HiddenNamespace()
        // 类的访问权限
        .Access(AccessFlags.Public)
        // 名称
        .Name("Demo5")
        // 带参构造函数
        .Ctor(item => item.Public().Param<int>("test").Body("int _test  = test;"))
        // 属性
        .Field(item =>  item.Public().Name("Age").Type<int>(); )
        // 属性
        .Field(item =>  item.Public().Name("Name").Type<string>(); )
        // 封装的方法
        .Property(item =>  item.Public().Name("Obj").Type<NClass>(); )
        .GetType();
    var script = builder.AssemblyBuilder.SyntaxTrees[0].ToString();
    System.Console.WriteLine(script);

运行结果

另外附上一个较为全面的例子

//构建二 使用了上面例子的type
//添加了该引用一直无效果,因此直接将TestAttribute放到了代码中
NatashaManagement.AddGlobalReference(typeof(TestAttribute));
NClass builder2 = NClass.UseScope();
var type2 = builder2
    .Public()
    // 类名称
    .Name("Demo51")
    // 注释
    .Summary("This is a test class;")
    // 添加只读的int变量ReadonlyField
    .PublicReadonlyField<int>("ReadonlyField")
    // 声明一个构造函数
    .Ctor(item => item.Public().Body("ReadonlyField = 10;"))
    // 私有变量声明
    .PrivateField<string>("_name", "[TestAttribute]")
    // 声明了TestAttribute属性的Get方法
    .Property(item => item
        .Public()
        .Attribute<TestAttribute>()
        .Type<string>()
        .Name("NameProperty")
        .OnlyGetter("return _name;"))
    // Get/Set方法
    .Property(item => item
        .Public()
        .Type("AnotherClass")
        .Name("AnotherProperty"))
    // 名为SetName,参数为string的返回值为_name的虚方法
    .Method(item => item
        .Public()
        .Virtrual()
        .Async()
        .Name("SetName")
        .Param<string>("name")
        .Body(@"_name = name;
                            return _name;")
        .Return<Task<string>>())
    // 在命名空间中额外添加一个AnotherClass方法
    .NamespaceBodyAppend("public class AnotherClass")
    .NamespaceBodyAppend("public class TestAttribute : Attribute  ")
    .GetType();
var script2 = builder2.AssemblyBuilder.SyntaxTrees[0].ToString();
// 打印
System.Console.WriteLine(script2);

运行结果

NEnum

枚举类

//没啥好说的。。。。
NEnum builder = NEnum.DefaultDomain();
var type = builder
    .NoGlobalUsing()
    .HiddenNamespace()
    .Access(AccessFlags.Public)
    .Name("EnumDemo")
    .EnumField("Apple", 1, "苹果")
    .EnumField("Orange", 2)
    .EnumField("Banana", 4)
    .GetType();
System.Console.Write(builder.AssemblyBuilder.SyntaxTrees[0].ToString());

运行结果

未完待续。。。

Natasha V1.3.6.0 的升级日志

开源库满足于个人,而完善于大众。

Natasha 自稳定版发布之后,众多老铁参与增强改进,感谢如下老铁的反馈:


1. 异常搜集

在 wenjq0911 建议下,添加了异常捕获,现 Natasha 的编译器已支持 Exception 字段,它将在整个编译周期中搜集异常。

        
  var fastBuilder = FastMethodOperator.New;
  fastBuilder.Complier.Exception;             //编译后异常会进入这里
  
  
  var fakeBuilder = FakeMethodOpeartor.New;
  fakeBuilder.Complier.Exception;
  
  
  var oopBuilder = new OopOperator();
  oopBuilder.Complier.Exception;
  
  
  if(Builder.Complier.Exception.ErrorFlag == ComplieError.None) 
  
        //编译成功!
     
  

UT地址:https://github.com/dotnetcore/Natasha/blob/master/test/NatashaUT/ExceptionTest.cs




2. Web环境

另外 wenjq0911 提供了 web 环境的运行信息,根据排查和调研,Natasha 现采用 AspNetCore 的 refs 子文件夹方式提供 web 应用程序的引用,配置文件内容已在 ReadMe 中更改。


<PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.2</TargetFramework>
    // 一定要加上这句话
    <PreserveCompilationContext>true</PreserveCompilationContext> 
    // WEB发布加 
    <MvcRazorExcludeRefAssembliesFromPublish>false</MvcRazorExcludeRefAssembliesFromPublish> 
</PropertyGroup>




3. 异步方法

在 Jello 的建议下,增加了异步方法的反解还原,并在 FastMethodOperator 中支持 UseAsync/AsyncFrom 等异步来源方法。


public static async void RunAsyncDelegate2()

    var delegateAction = FastMethodOperator.New
    
                        .UseAsync()
                        
                        .Param<string>("str1")
                        .Param<string>("str2")
                        
                        .MethodBody(@"
                            await Task.Delay(1000);
                            string result = str1 +"" ""+ str2;
                            Console.WriteLine(result);
                            return result;"
                            
                        .Return<Task<string>>()
                        
                        .Complie();

    string result = await ((Func<string, string, Task<string>>)delegateAction)?.Invoke("Hello", "World1!");
    Assert.Equal("Hello World1!", result);
     
 

UT地址:https://github.com/dotnetcore/Natasha/blob/master/test/NatashaUT/AsyncMethoddTest.cs




4. 智能方法

Wayne 和 Dennis 在异步的基础上给出了体验优化的建议,Natasha 的Complier 函数目前支持方法参数及返回值的智能解析:

在不指定参数的情况下默认使用 TDelegate 的参数;

在不指定返回值的情况下,默认使用 TDelegate 的返回类型;


 var delegateAction = FastMethodOperator.New

                .UseAsync()
                .MethodBody(@"
                            string result = arg1 +"" ""+ arg2;
                            Console.WriteLine(result);
                            return result;")

                .Complie<Func<string, string, Task<string>>>();

string result =await delegateAction?.Invoke("Hello", "World2!");
 Assert.Equal("Hello World2!", result);    

UT地址:https://github.com/dotnetcore/Natasha/blob/master/test/NatashaUT/AsyncMethoddTest.cs




5. 外部文件与运行时脚本混合编译

在 Teng 的建议下,增加了外部文件和运行时脚本混合编译的功能。使用 LoadFile方法将外部 Dll 文件引入运行时,并添加到编译列表中。LoadFile 方法是在IComplier 抽象编译器中实现的,所以,只要 Builder 类实现了编译器,都将拥有此方法。


using System;

namespace ClassLibrary1

    public class Class1
    
        public void Show1()
        
            Console.WriteLine("RunShow1");
        

        public static void Show2()
        
            Console.WriteLine("RunShow2");
        
    

string text = @"
    using System;
    using System.Text;
    using ClassLibrary1;
 
    namespace HelloWorld
    
       public class Test
       
            public override string ToString()
            
                Class1 a = new Class1();
                a.Show1();
                Class1.Show2();
                return ""11"";
            
       
    ";
    
//Class1 来自于 ClassLibrary1.dll


OopComplier oop = new OopComplier(); //OopComplier在2.0中移除
oop.LoadFile(@"D:\Project\IlTest\ClassLibrary1\bin\Debug\netstandard2.0\ClassLibrary1.dll");
Type type = oop.GetClassType(text);


//调用
var a = Activator.CreateInstance(type);
Console.WriteLine(a.ToString());

(2.0版本引擎升级后会将此方法包装进程序集域的操作类中)




6. 继承、重写与实现

allmyfantasy 建议下,完善了类、接口、抽象类、虚方法的实现。


 ProxyOperator<Interface> builder = new ProxyOperator<Interface>();
 builder.OopName("InterfaceClass");
 builder["InterfaceMethod"] = "return 123456;";  // public method
 builder.Compile();
 var test = builder.Create("InterfaceClass");


 ProxyOperator<Class> builder = new ProxyOperator<Class>();
 builder.OopName("TestClass");
 builder["NormalMethod"] = "return 123456;";     //new method
 builder["VirtualMethod"] = "return 123456;";    //override method
 builder.Compile();
 dynamic test = Activator.CreateInstance(builder.TargetType);
 
 
 ProxyOperator<Abstract> builder = new ProxyOperator<Abstract>();
 builder.OopName("AbstractClass");
 builder["AbstractMethod"] = "return 123456;";   //overrider method
 builder.Compile();
 var test = builder.Create("AbstractClass");
 

UT地址:https://github.com/dotnetcore/Natasha/blob/master/test/NatashaUT/ProxyTest.cs




7. 添加包装类

guodf、Teng、WeihanLi 的建议下,添加包装类提升使用体验。

  var result = NewClass.Create(Action<OopOperator> action);
  var result = NewInterface.Create(Action<OopOperator> action);
  var result = NewStruct.Create(Action<OopOperator> action);
  
  var type = result.Type;
  var error = result.Exception; 
  
  
  var result = NewMethod.Create(Action<FastMethodOperator> action);

  var error = result.Exception;
  var method = result.Method;
  method();




8. 支持非安全方法

根据 FUTURE* 的需求,支持了非安全方法的编译,现可以使用 UseUnsafe 方法来实现。




9. 快速实现动态功能

增加了 NFunc/NAction 两种快速实现委托的操作类。
//NFunc 和 NAction 支持的方法:
// 普通方法:Delegate
// 异步方法:AsyncDelegate
// 非安全方法:UnsafeDelegate
// 非安全异步方法:UnsafeAsyncDelegate

var action = NFunc<string, string, Task<string>>.UnsafeAsyncDelegate(@"
                            string result = arg1 +"" ""+ arg2;
                            Console.WriteLine(result);
                            return result;");

string result = await action("Hello", "World1!");
//result = "Hello World1!"




10. 枚举类型构建与编译


var script = new OopOperator()
    .HiddenNameSpace().ChangeToEnum()
    .OopAccess(AccessTypes.Public).OopName("EnumUT1")
    .EnumField("Apple")
    .EnumField("Orange",2)
    .EnumField("Banana")
    .Builder().Script;

 /* result: 
public enum EnumUT1
   Apple,
   Orange=2,
   Banana*/
   

(2.0版本将在此基础上增加封装类)




11. 日志加深一级

\netcoreapp2.2\log\2019\08月19日\17时39分

(2.0版本将进行优化和改动)




鸣谢贡献者:

感谢 WeihanLi 帮忙做了 CodeReview 的工作。
感谢 Teng 帮忙做了 WikiReview 的工作。

Natasha2.0 将兼容 Core3.0 版本,除升级优化引擎之外还将支持隔离编译与卸载功能。后续还会跟随合理需求进行升级维护, 感谢各位的支持和鼓励。
欢迎访问主页并扫码进入 Natasha 生态群:https://github.com/dotnetcore/Natasha
孵化组正在进行的项目:DeepClone/NMapper/NCaller

以上是关于Natasha 高级编译类 - 第一部分的主要内容,如果未能解决你的问题,请参考以下文章

Natasha 高级编译类 - 第三部分

Natasha 编译单元

第一部分 计算机编程语言

动态编译库 Natasha 5.0 版本发布

Natasha 4.0 探索之路系列 基本的动态编译

Java学习-第一部分-第二阶段-第一节:面向对象编程(高级)