9.8 KiB
Object Runtime And Introspection
文档类型:语法主线 是否可直接用于生成代码:仅部分 是否含已验证可执行示例:是 是否含已验证反例:否 遇到不确定时跳转到:09_objects_and_classes.md、24_builtin_runtime_objects.md、32_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当前至少已验证可以读出functionname、returntype、classname这几个字段。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.
已验证运行结果:
- 依次输出
ClassA、1 - 说明
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.
已验证运行结果:
- 依次输出
1、2 - 说明当前最小样例里,构造函数内部对象状态是
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.
已验证运行结果:
- 依次输出
1、0、3 - 说明属性写入函数里
tslassigning为1 - 属性读取函数里
tslassigning为0
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.
已验证运行结果:
- 依次输出
7、11 - 说明
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.
已验证运行结果:
- 依次输出
7、11 - 说明
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.
已验证运行结果:
- 依次输出
add、sum_t、a - 说明
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.
已验证运行结果:
- 依次输出
2、1、3 - 说明
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 Zero、destroy、O2 to Zero - 说明只清空第一个别名时对象还不会释放
- 最后一个引用清空后才会触发
destroy()
跳转指引
- 回看类的基础语法:见 09_objects_and_classes.md
- 回看函数值与基础调用:见 06_functions_and_calls.md
- 看运行时内置对象:见 24_builtin_runtime_objects.md
- 看对象算符重载:见 32_object_overloads_and_iteration.md