Natasha 4.0 探索之路系列(四) 模板 API

AzulX發表於2022-01-23

Natasha 模板

Natasha 在編譯單元的基礎上進行了封裝整理, 並提供了多種模板幫助開發者構建功能.
使用此篇的 API 前提是您對 C# 非常熟悉, 對系統的一些型別足夠了解.
據此 Natasha 將拒絕與科普相關 C# 的 issue , 望諒解.
目前已有的模板:

模板名 用途
NClass 構建型別指令碼
NStuct 構建結構體指令碼
NEnum 構建列舉指令碼
NInterface 構建介面指令碼
NRecord 構建記錄指令碼
NDelegate 快速建立委託
FastOperator 快速建立方法的操作類
FakeOperator 方法複製的操作類

使用方法

建立類


//萬年不變的預熱
NatashaInitializer.Preheating();

//在隨機域內建立一個型別
NClass builder = NClass.RandomDomain();

var type = builder
    .Public()
    .Summary("This is a test class;")
    /*
     namespace NatashaDynimacSpace
     {
       /// <summary>
       /// This is a test class;
       /// </summary>
       public class Nee7e202ee18c413dacae62af6b106c6e
    */


    .PublicReadonlyField<int>("ReadonlyField")
    //public readonly System.Int32 ReadonlyField;


    .Ctor(item => item.Public().Body("ReadonlyField = 10;"))
    /*
     public Nee7e202ee18c413dacae62af6b106c6e()
     {
              ReadonlyField = 10;
     }
    */


    .PrivateField<string>("_name", "[MyTestAttribute]")
    //[MyTestAttribute]
    //private System.String _name;


    .Property(item => item
        .Public()
        .Attribute<MyTestAttribute>()
        .Type<string>()
        .Name("NameProperty")
        .OnlyGetter("return _name;"))
     /*[NatashaFunctionUT.Template.Compile.MyTestAttribute]
     public System.String NameProperty
     {
            get
            {
                return _name;
            }
     }*/


    .Property(item => item
        .Public()
        .Type("AnotherClass")
        .Name("AnotherProperty"))
    //public AnotherClass AnotherProperty { get; set; }


    .Method(item => item
        .Public()
        .Virtrual()
        .Async()
        .Name("SetName")
        .Param<string>("name")
        .Body(@"_name = name;return _name;")
        .Return<Task<string>>())
     /*
      public virtual async System.Threading.Tasks.Task<System.String> SetName(System.String name)
      {
            _name = name;
            return _name;
      }
    */

    .NamespaceBodyAppend("public class AnotherClass{}")
    /*
     public class AnotherClass
     {
     }
    */
    .GetType();

建立結構體

//建立一段如下的結構
/*
[StructLayout(LayoutKind.Explicit)]
public struct EnumUT1
{
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
    public System.Int32 Apple;
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
    public System.Int32 Orange;
}";
*/
NStruct builder = NStruct.RandomDomain();
           
var type = builder
  .HiddenNamespace()
  .AttributeAppend("[StructLayout(LayoutKind.Explicit)]")
  .Access(AccessFlags.Public)
  .Name("EnumUT1")
  .Field(item => { item.AttributeAppend<FieldOffsetAttribute>("0").Public().Name("Apple").Type<int>(); })
  .Field(item => { item.AttributeAppend<FieldOffsetAttribute>("0").Public().Name("Orange").Type<int>(); })
  .GetType();
var script = builder.AssemblyBuilder.SyntaxTrees[0].ToString();

建立列舉

//建立以下列舉
/*
public enum EnumUT1
{
    /// <summary>
    /// 蘋果
    /// </summary>
    Apple = 1,
    Orange = 2,
    Banana
}
*/
NEnum builder = NEnum.RandomDomain();
           
var type = builder
  .NoGlobalUsing()
  .HiddenNamespace()
  .Access(AccessFlags.Public)
  .Name("EnumUT1")
  .EnumField("Apple", 1,"蘋果")
  .EnumField("Orange", 2)
  .EnumField("Banana")
  .GetType();
var script = builder.AssemblyBuilder.SyntaxTrees[0].ToString();

建立介面

//建立以下介面
/*
using System;

public interface Interface1
{
    System.String Abc { get; set; }

    System.Int32 Test(System.String p);
}
*/

var builder = NInterface.RandomDomain();
var type = builder
    .NoGlobalUsing()
    .HiddenNamespace()
    .Access(AccessFlags.Public)
    .Name("Interface1")
    .Property(item => item.Type<string>().Name("Abc"))
    .Method(item => item.Name("Test").Param<string>("p").Return<int>())
    .GetType();
var script = builder.AssemblyBuilder.SyntaxTrees[0].ToString();

使用 NDelegate 快速建立委託

NDelegate 實現了自定義委託/系統委託( Action & Func ) 的建立方法.
委託的引數名/引數型別/返回值與系統委託一一對應.
針對系統委託,如果在新增方法體時還不清楚對應的引數名可以 F12 到對應的 Action/Func 定義中檢視引數名.

以下舉例了常見的系統委託引數名

  • Action<T1> 定義的引數名為 obj; 而 Action<T1,T2> 引數名為: arg1 , arg2;
  • Func<T1,R> 定義的引數名為 arg; 而 Func<T1,T2,R> 引數名為: arg1 , arg2;

使用程式碼:

  • 用法1: 自定義委託
public delegate int TestDelegate(string value);
var action = NDelegate
              .RandomDomain()
              .Delegate<TestDelegate>(@"return (value+""hello"").Length;");
int result = action("Hello");
  • 用法2: 系統委託
var action = NDelegate
              .RandomDomain()
              //建立非託管的非同步委託,對應的系統委託: Func<string, string, Task<string>>
              .UnsafeAsyncFunc<string, string, Task<string>>(@"return arg1 +"" ""+ arg2;");

string result = await action("Hello", "World1!");
Assert.Equal("Hello World1!", result);

另外,我將在這個目錄下上傳一些奇奇怪怪的構建,包括一些新科技的應用,和有趣的語義擴充套件. UT連結

其他 API

模板比起基礎構建,除了提供了方便的鏈式 API ,還有 Using 管理.

  • NoGlobalUsing()/UseGlobalUsing(): 是否使用預設(全域性)域 using 覆蓋.(預設使用)
  • LoadDomainUsing()/NotLoadDomainUsing(): 是否載入模板所在隨機域中的 using.(預設使用)

結尾

實際上 Natasha 模板是針對大部分 C# 的資料型別進行的基礎封裝, 還可以進一步定製封裝,比如以 NClass 為基礎建立一個 Web COntroller 模板, 如果需要其他擴充套件, 可以先了解一下原始碼結構,或與我討論進行擴充套件.

相關文章