自定义标签

JNTemplate可以很方便的自定义标签,本文档假定您已经有一定的IL基本知识。自定义标签需要定义以下四个对象:

  1. 标签类,必须实现ITag接口。
  2. 标签解析委托Func<TemplateParser, Nodes.TokenCollection, Nodes.ITag>
  3. 标签编译委托Func<ITag, CompileContext, System.Reflection.MethodInfo>
  4. 标签类型推断委托Func<ITag, CompileContext, Type> guessFunc)

下面将实现一个自定义标签,写法是${:text},作用是直接输出冒号后的文本内容,根据该DEMO,让大家熟悉JNTemplate标签的自定义方流程。

定义标签类

定义一个类,继承自ITag,为了方便开发,建议同时继承自标签基类Tag,其它所需参数自己随意定义。

public class TestTag : Tag, ITag
{
    /// <summary>
    /// 定义一个属性Document存放冒号后的文本
    /// </summary>
    public string Document { get; set; }
}

定义解析委托

该委托将告诉引擎,如何解析你的标签。

Func<TemplateParser, Nodes.TokenCollection, Nodes.ITag> action = (p, tc) => {
        //判断是否是我们自定义的TestTag
        if (tc.Count == 2 && tc.First.Text == ":")
        {
            return new TestTag
            {
                Document = tc[1].Text
            };
        }
        //不是返回NULL
        return null;
}

TIP

如果当前集合不符合自定义标签条件,直接返回null即可。

定义编译委托

该委托将告诉引擎,如何编译你定义的标签。该步骤要求有一定的IL知识。

Func<ITag, CompileContext, MethodInfo> action1 = (tag, c) => {
    var t = tag as TestTag;
    var mb = c.CreateReutrnMethod<TestTag>(typeof(string));//定义一个方法
    var il = mb.GetILGenerator();//获取IL Generator
    il.Emit(OpCodes.Ldstr, t.Document); //将Document以字符串引用推送到堆上
    il.Emit(OpCodes.Ret);//返回结果
    return mb.GetBaseDefinition();//生成方法
}

定义推断委托

该委托的作用是告诉引擎,该标签的返回结果是什么类型。

//TestTag 返回的是字符串类型,不需要做推断
Func<ITag, CompileContext, Type> action2 = (tag, c) => typeof(string);

注册标签

以上内容都定义好了,我们可以通过Engine.Register<ITag>(...)方法来注册我们定义的标签。

Engine.Register<TestTag>(action,action1,action2);

输出

到这一步,我们标签定义已经完成,我们可以运行下面的代码检测实际效果:

var templateContent = "${:hello}";
var template = Engine.CreateTemplate(templateContent);
var render = template.Render();

Assert.Equal("hello", render);

WARNING

注意:自定义标签为引擎的高级用法,如果您对引擎不够熟悉,我们不推荐您使用本功能,不正确的写法可能会影响整个引擎的运行速度。

Last Updated:
Contributors: 翅膀的初衷