📝 docs(tsl): rebuild canonical syntax and routing manual
This commit is contained in:
@@ -0,0 +1,399 @@
|
||||
# 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)
|
||||
Reference in New Issue
Block a user