playbook/docs/tsl/syntax/23_object_runtime_and_intro...

9.8 KiB
Raw Blame History

Object Runtime And Introspection

文档类型:语法主线 是否可直接用于生成代码:仅部分 是否含已验证可执行示例:是 是否含已验证反例:否 遇到不确定时跳转到:09_objects_and_classes.md24_builtin_runtime_objects.md32_object_overloads_and_iteration.md

手册位置:第 23 篇,共 32 篇。上一篇:22_namespace_libpath_and_unit_runtime.md。下一篇:24_builtin_runtime_objects.md

这一篇收拢对象模型里不适合继续堆在基础类主线里的运行时内容:类信息、函数句柄、对象状态、引用计数、运行时对象枚举。

这一篇解决什么问题

回答“类已经会声明、继承、构造之后,怎样检查类信息、函数信息和对象运行时状态”。

必须记住的规则

  • 对象值当前可以用 ifObj(...) 做显式判定。
  • class(Name)FindClass("Name") 当前都可以拿到类类型。
  • obj is classType 当前已验证可直接拿类类型变量来做实例判定。
  • FindClass("ParentName", obj) 当前已验证可以把实例对象降成指定父类视图。
  • obj.ClassInfo(1) 当前已验证会返回类类型,并且这个类类型可以继续交给 CreateObject(...)
  • obj.ClassInfo() 当前至少已验证可以直接读出 ["classname"]
  • objectstate(self) 在构造函数内部的最小已验证结果是 1;构造结束后对实例再取 objectstate(obj) 的最小已验证结果是 2
  • tslassigning 在属性写入函数里输出 1,在属性读取函数里输出 0
  • FindFunction("MethodName", obj) 当前已验证可以拿到实例方法句柄。
  • FindFunction("MethodName", class(A)) 当前已验证可以拿到类方法句柄。
  • ThisFunction(obj.Method)ThisFunction(class(A).Method) 当前也已验证可用。
  • 当前最稳的句柄调用方式是 f.do(...)
  • FindOverLoad(argc, "Name", obj) 当前已验证可以按参数个数取到对应重载方法。
  • FunctionInfo 当前至少已验证可以读出 functionnamereturntypeclassname 这几个字段。
  • TSLObjects(1) 当前已验证会按类名分组返回对象信息,并且分组项里的 "obj" 字段可以重新拿到可调用对象。
  • 对象赋值会延长对象存活;当前最小样例里,只有最后一个引用清空后才会触发 destroy()

已验证语法

对象值的最小显式判定:

代码块身份:已验证可执行示例

program test;
begin
    obj := CreateObject("TStringList");
    WriteLn(ifObj(obj));
end.

已验证运行结果:

  • 输出 1
  • 说明 CreateObject(...) 得到的对象值当前可以用 ifObj(...) 判定

FindClass(...) 与类类型变量:

代码块身份:已验证可执行示例

program test;
type A = class
    class function FucA();
    begin
        return "ClassA";
    end;
end;
begin
    classA := FindClass("A");
    obj := new A();
    WriteLn(classA.FucA());
    WriteLn(obj is classA);
end.

已验证运行结果:

  • 依次输出 ClassA1
  • 说明 FindClass("A") 当前可以拿到类类型
  • 说明类类型变量可以直接调用类方法
  • 也说明 obj is classA 这种“实例对类类型变量做判定”的写法当前可用

FindClass("Parent", obj) 的父类视图:

代码块身份:已验证可执行示例

program test;
type ClassA = class
    function Fuc(); virtual;
    begin
        return "ClassA";
    end;
end;
type ClassB = class(ClassA)
    function Fuc(); override;
    begin
        return "ClassB";
    end;
end;
begin
    objb := new ClassB();
    obj := FindClass("ClassA", objb);
    WriteLn(obj.Fuc());
end.

已验证运行结果:

  • 输出 ClassA
  • 说明 FindClass("ClassA", objb) 当前可以把子类实例降成父类视图
  • 也说明之后的方法分派会按父类视图执行

ClassInfo(1) 返回类类型:

代码块身份:已验证可执行示例

program test;
type A = class
    value;
end;
begin
    obj := new A();
    cls := obj.ClassInfo(1);
    obj2 := CreateObject(cls);
    WriteLn(obj2 is class(A));
end.

已验证运行结果:

  • 输出 1
  • 说明 obj.ClassInfo(1) 当前可以返回类类型
  • 也说明这个类类型可以继续交给 CreateObject(...)

ClassInfo() 返回的映射字段:

代码块身份:已验证可执行示例

program test;
type A = class
end;
begin
    obj := new A();
    info := obj.ClassInfo();
    WriteLn(info["classname"]);
end.

已验证运行结果:

  • 输出 a
  • 说明 ClassInfo() 当前至少可以直接读出 ["classname"]
  • 当前这个最小例子里,类名表现为小写标识符

objectstate(...)

代码块身份:已验证可执行示例

program test;
type ca = class
    static sca;
    function create(n);
    begin
        sca := self;
        WriteLn(objectstate(self));
    end;
end;
begin
    oa := new ca("abc");
    WriteLn(objectstate(oa));
end.

已验证运行结果:

  • 依次输出 12
  • 说明当前最小样例里,构造函数内部对象状态是 1
  • 构造结束后,再对实例取 objectstate(...) 会得到 2

tslassigning

代码块身份:已验证可执行示例

program test;
type ca = class
    value;
    property c read getc write setc;
    function setc(v);
    begin
        WriteLn(tslassigning);
        value := v;
    end;
    function getc();
    begin
        WriteLn(tslassigning);
        return value;
    end;
end;
begin
    o := new ca();
    o.c := 3;
    WriteLn(o.c);
end.

已验证运行结果:

  • 依次输出 103
  • 说明属性写入函数里 tslassigning1
  • 属性读取函数里 tslassigning0

FindFunction(...) 查找实例方法和类方法:

代码块身份:已验证可执行示例

program test;
type A = class
    function Add(x, y);
    begin
        return x + y;
    end;
    class function AddClass(x, y);
    begin
        return x + y;
    end;
end;
begin
    obj := new A();
    f1 := FindFunction("Add", obj);
    f2 := FindFunction("AddClass", class(A));
    WriteLn(f1.do(3, 4));
    WriteLn(f2.do(5, 6));
end.

已验证运行结果:

  • 依次输出 711
  • 说明 FindFunction(..., obj) 当前能拿到实例方法句柄
  • 说明 FindFunction(..., class(A)) 当前能拿到类方法句柄
  • 也说明句柄调用方式 f.do(...) 当前稳定可用

ThisFunction(...) 也可以直接拿方法句柄:

代码块身份:已验证可执行示例

program test;
type A = class
    function Add(x, y);
    begin
        return x + y;
    end;
    class function AddClass(x, y);
    begin
        return x + y;
    end;
end;
begin
    obj := new A();
    f1 := ThisFunction(obj.Add);
    f2 := ThisFunction(class(A).AddClass);
    WriteLn(f1.do(3, 4));
    WriteLn(f2.do(5, 6));
end.

已验证运行结果:

  • 依次输出 711
  • 说明 ThisFunction(...) 当前也可以稳定得到实例方法和类方法句柄

FindOverLoad(...)

代码块身份:已验证可执行示例

program test;
type TestClass = class
    function fun(p1, p2); overload;
    begin
        return p1 + p2;
    end;
    function fun(p1); overload;
    begin
        return p1 + 10;
    end;
end;
begin
    t := FindOverLoad(2, "fun", CreateObject("TestClass"));
    WriteLn(t.do(1, 2));
end.

已验证运行结果:

  • 输出 3
  • 说明 FindOverLoad(2, "fun", obj) 当前可以按参数个数拿到对应重载方法

FunctionInfo 的最小已验证字段:

代码块身份:已验证可执行示例

program test;
type A = class
    class function Add(a: lhs; b: rhs): sum_t;
    begin
        return a + b;
    end;
end;
begin
    f := ThisFunction(class(A).Add);
    info := f.FunctionInfo;
    WriteLn(info["functionname"]);
    WriteLn(info["returntype"]);
    WriteLn(info["classname"]);
end.

已验证运行结果:

  • 依次输出 addsum_ta
  • 说明 FunctionInfo["functionname"]["returntype"]["classname"] 当前都可直接读取
  • 当前这个最小例子里,返回的函数名和类名表现为小写标识符

TSLObjects(1)

代码块身份:已验证可执行示例

program test;
type TestClass01 = class
    value;
    function create(_value);
    begin
        value := _value;
    end;
    class function add(x, y);
    begin
        return x + y;
    end;
end;
begin
    objA := new TestClass01(100);
    objB := new TestClass01(101);
    objsInfo := TSLObjects(1);
    WriteLn(length(objsInfo["TestClass01"]));
    newObjA := objsInfo["TestClass01"][0, "obj"];
    WriteLn(newObjA is class(TestClass01));
    WriteLn(newObjA.add(1, 2));
end.

已验证运行结果:

  • 依次输出 213
  • 说明 TSLObjects(1) 当前可以按类名拿到对象分组
  • 分组项里的 "obj" 字段当前可以重新拿到可调用对象

引用计数的最小行为:

代码块身份:已验证可执行示例

program test;
type T1 = class
    function destroy();
    begin
        WriteLn("destroy");
    end;
end;
begin
    o1 := new T1();
    o2 := o1;
    o1 := 0;
    WriteLn("O1 to Zero");
    o2 := 0;
    WriteLn("O2 to Zero");
end.

已验证运行结果:

  • 依次输出 O1 to ZerodestroyO2 to Zero
  • 说明只清空第一个别名时对象还不会释放
  • 最后一个引用清空后才会触发 destroy()

跳转指引