# Object Runtime And Introspection 文档类型:语法主线 是否可直接用于生成代码:仅部分 是否含已验证可执行示例:是 是否含已验证反例:否 遇到不确定时跳转到:[09_objects_and_classes.md](09_objects_and_classes.md)、[24_builtin_runtime_objects.md](24_builtin_runtime_objects.md)、[32_object_overloads_and_iteration.md](32_object_overloads_and_iteration.md) 手册位置:第 23 篇,共 32 篇。上一篇:[22_namespace_libpath_and_unit_runtime.md](22_namespace_libpath_and_unit_runtime.md)。下一篇:[24_builtin_runtime_objects.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` 当前至少已验证可以读出 `functionname`、`returntype`、`classname` 这几个字段。 - `TSLObjects(1)` 当前已验证会按类名分组返回对象信息,并且分组项里的 `"obj"` 字段可以重新拿到可调用对象。 - 对象赋值会延长对象存活;当前最小样例里,只有最后一个引用清空后才会触发 `destroy()`。 ## 已验证语法 对象值的最小显式判定: 代码块身份:已验证可执行示例 ```tsl program test; begin obj := CreateObject("TStringList"); WriteLn(ifObj(obj)); end. ``` 已验证运行结果: - 输出 `1` - 说明 `CreateObject(...)` 得到的对象值当前可以用 `ifObj(...)` 判定 `FindClass(...)` 与类类型变量: 代码块身份:已验证可执行示例 ```tsl 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. ``` 已验证运行结果: - 依次输出 `ClassA`、`1` - 说明 `FindClass("A")` 当前可以拿到类类型 - 说明类类型变量可以直接调用类方法 - 也说明 `obj is classA` 这种“实例对类类型变量做判定”的写法当前可用 `FindClass("Parent", obj)` 的父类视图: 代码块身份:已验证可执行示例 ```tsl 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)` 返回类类型: 代码块身份:已验证可执行示例 ```tsl 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()` 返回的映射字段: 代码块身份:已验证可执行示例 ```tsl program test; type A = class end; begin obj := new A(); info := obj.ClassInfo(); WriteLn(info["classname"]); end. ``` 已验证运行结果: - 输出 `a` - 说明 `ClassInfo()` 当前至少可以直接读出 `["classname"]` - 当前这个最小例子里,类名表现为小写标识符 `objectstate(...)`: 代码块身份:已验证可执行示例 ```tsl 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. ``` 已验证运行结果: - 依次输出 `1`、`2` - 说明当前最小样例里,构造函数内部对象状态是 `1` - 构造结束后,再对实例取 `objectstate(...)` 会得到 `2` `tslassigning`: 代码块身份:已验证可执行示例 ```tsl 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. ``` 已验证运行结果: - 依次输出 `1`、`0`、`3` - 说明属性写入函数里 `tslassigning` 为 `1` - 属性读取函数里 `tslassigning` 为 `0` `FindFunction(...)` 查找实例方法和类方法: 代码块身份:已验证可执行示例 ```tsl 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. ``` 已验证运行结果: - 依次输出 `7`、`11` - 说明 `FindFunction(..., obj)` 当前能拿到实例方法句柄 - 说明 `FindFunction(..., class(A))` 当前能拿到类方法句柄 - 也说明句柄调用方式 `f.do(...)` 当前稳定可用 `ThisFunction(...)` 也可以直接拿方法句柄: 代码块身份:已验证可执行示例 ```tsl 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. ``` 已验证运行结果: - 依次输出 `7`、`11` - 说明 `ThisFunction(...)` 当前也可以稳定得到实例方法和类方法句柄 `FindOverLoad(...)`: 代码块身份:已验证可执行示例 ```tsl 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` 的最小已验证字段: 代码块身份:已验证可执行示例 ```tsl 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. ``` 已验证运行结果: - 依次输出 `add`、`sum_t`、`a` - 说明 `FunctionInfo["functionname"]`、`["returntype"]`、`["classname"]` 当前都可直接读取 - 当前这个最小例子里,返回的函数名和类名表现为小写标识符 `TSLObjects(1)`: 代码块身份:已验证可执行示例 ```tsl 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. ``` 已验证运行结果: - 依次输出 `2`、`1`、`3` - 说明 `TSLObjects(1)` 当前可以按类名拿到对象分组 - 分组项里的 `"obj"` 字段当前可以重新拿到可调用对象 引用计数的最小行为: 代码块身份:已验证可执行示例 ```tsl 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 Zero`、`destroy`、`O2 to Zero` - 说明只清空第一个别名时对象还不会释放 - 最后一个引用清空后才会触发 `destroy()` ## 跳转指引 - 回看类的基础语法:见 [09_objects_and_classes.md](09_objects_and_classes.md) - 回看函数值与基础调用:见 [06_functions_and_calls.md](06_functions_and_calls.md) - 看运行时内置对象:见 [24_builtin_runtime_objects.md](24_builtin_runtime_objects.md) - 看对象算符重载:见 [32_object_overloads_and_iteration.md](32_object_overloads_and_iteration.md)