自定义标签
JNTemplate可以很方便的自定义标签,本文档假定您已经有一定的IL基本知识。自定义标签需要定义以下四个对象:
- 标签类,必须实现
ITag
接口。 - 标签解析委托
Func<TemplateParser, Nodes.TokenCollection, Nodes.ITag>
- 标签编译委托
Func<ITag, CompileContext, System.Reflection.MethodInfo>
- 标签类型推断委托
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
注意:自定义标签为引擎的高级用法,如果您对引擎不够熟悉,我们不推荐您使用本功能,不正确的写法可能会影响整个引擎的运行速度。