# 05 对象模型(class/unit) 本章整理 Object TSL 的类、对象、属性、方法与相关语法。 ## 目录 - [Object TSL](#object-tsl) - [内容](#内容) - [类和对象](#类和对象) - [内容](#内容-1) - [概述](#概述) - [类类型声明的语法](#类类型声明的语法) - [类类型声明的位置](#类类型声明的位置) - [类的实例化](#类的实例化) - [对象成员的访问](#对象成员的访问) - [类继承和作用域](#类继承和作用域) - [内容](#内容-2) - [继承](#继承) - [作用域](#作用域) - [字段](#字段) - [内容](#内容-3) - [字段简介](#字段简介) - [static 静态字段](#static静态字段) - [const 常量成员](#const常量成员) - [方法](#方法) - [内容](#内容-4) - [方法简介](#方法简介) - [声明和实现](#声明和实现) - [覆盖(override)](#覆盖override) - [多态](#多态) - [隐藏](#隐藏) - [重载(overload)](#重载overload) - [构造函数](#构造函数) - [析构函数](#析构函数) - [指定类](#指定类) - [Self](#self) - [类方法](#类方法) - [属性 Property](#属性property) - [索引器(index)](#索引器index) - [TSL 对象的创建](#tsl对象的创建) - [内容](#内容-5) - [New](#new) - [CreateObject](#createobject) - [类信息](#类信息) - [内容](#内容-6) - [FindClass](#findclass) - [ClassInfo](#classinfo) - [objectstate](#objectstate) - [tslassigning](#tslassigning) - [对象的引用计数](#对象的引用计数) - [IS 关键字](#is关键字) - [函数信息](#函数信息) - [内容](#内容-7) - [FindOverLoad](#findoverload) - [TSLObjects](#tslobjects) - [FindFunction](#findfunction) - [ThisFunction](#thisfunction) - [FunctionInfo](#functioninfo) - [算符重载](#算符重载) - [内容](#内容-8) - [Operator](#operator) - [算符重载的案例](#算符重载的案例) - [面向对象的 Operator 重载支持[]](#面向对象的operator重载支持) - [面向对象的 Operator 算符重载支持++,--,+=,-=](#面向对象的operator算符重载支持) - [单元中的类](#单元中的类) - [内容](#内容-9) - [继承单元中的类](#继承单元中的类) - [构造单元中的类实例](#构造单元中的类实例) - [预定义:ParentClassInUnit](#预定义parentclassinunit) - [单元中的类-应用实例](#单元中的类-应用实例) - [TSL 内置对象使用大全](#tsl内置对象使用大全) - [内容](#内容-10) - [TSL 内置对象使用大全简介](#tsl内置对象使用大全简介) - [FTP 对象](#ftp对象) - [TRSA](#trsa) - [TCipher](#tcipher) - [TStringList 对象](#tstringlist对象) - [THashedStringList 对象](#thashedstringlist对象) - [TStream 对象](#tstream对象) - [TMemoryStream 对象](#tmemorystream对象) - [THandleStream 对象](#thandlestream对象) - [TFileStream 对象](#tfilestream对象) - [TIniFile 对象](#tinifile对象) - [TMemIniFile 对象](#tmeminifile对象) - [TRegistryIniFile 对象](#tregistryinifile对象) - [TWebResponse 对象](#twebresponse对象) - [TWebRequest 对象](#twebrequest对象) - [TCookieCollection 对象](#tcookiecollection对象) - [TCookie 对象](#tcookie对象) - [TSessionMan 对象](#tsessionman对象) - [TSession 对象](#tsession对象) - [SMTP 对象](#smtp对象) - [Pop3 对象](#pop3对象) - [MailMsg 对象](#mailmsg对象) - [MessagePart 对象](#messagepart对象) ## Object TSL ### 内容 - 类和对象 - 类继承和作用域 - 字段 - 方法 - 属性 Property - 索引器(index) - TSL 对象的创建 - 类信息 - IS 关键字 - 函数信息 - 算符重载 - 单元中的类 - TSL 内置对象使用大全 ### 类和对象 面向对象的概念是相对于面向过程的 面向过程的表现形式是函数,数据以参数、系统参数、全局变量的模式传导进函数 面向对象的表现形式是类,数据以成员变量的方式存贮在类变量中,而具体的功能以成员函数的方式存在 面向对象的最原始的目的在于封装,将数据与多种方法封装在一起 此外,继承、多态等也是面向对象的特性 #### 内容 - 概述 - 类类型声明的语法 - 类类型声明的位置 - 类的实例化 - 对象成员的访问 #### 概述 类(或者类类型)定义了一个结构,抽象地,这个结构既可以包括数据,也可以包括行为; 具体地,类可以包括字段、方法和属性; 类的字段、方法和属性被称为它的成员。 类的实例叫做对象; > > 字段在本质上是一个对象的变量。和记录的字段类似,类的字段表示一个类实例的数据项; > > 方法是一个函数,它和类相关联。绝大多数方法作用在对象(也就是类的实例)上,其它一些方法(称为类方法)作用在类上面。 > > 属性被看作是访问对象的数据的接口,对象的数据通常用字段来存储。属性可以决定数据如何被读取或修改。属性在被引用的时候就像一个字段,但被实现时候可以是一个方法。 声明了类以后,程序员可以创建作为此类的实例对象。尽管有时类和对象叫法可互换,但它们是不同的概念。类定义对象的类型,但它不是对象本身。对象是基于类的具体实体,有时称为类的实例。 ```text Type MyClass = Class End; ``` 上面代码声明了一个类类型 ```text Obj:=createObject("MyClass"); ``` 上面代码创建了类 MyClass 的实例. 创建类的实例后,将向程序员传递回对该对象的引用。 在前面的示例中,obj 是对基于 MyClass 的对象的引用。此引用指向了新对象,但不包含对象数据本身。 #### 类类型声明的语法 ```text type className = class ([BaseClass1[,BaseClass2,…]]) private //作用域关键字,private表示下面声明的是私有化成员 //memberList Public //作用域关键字,public表示公开成员,不写此类关键字时默认为public //memberList function Create();overload;//初始化--构造函数--可省 function Destroy();//析构函数--可省 function func1();//成员方法 end; ``` 说明: Type 是一个关键字,说明要声明一个类型,Class 也是一个关键字,表示要声明一个类类型。 className 是要声明的你自己定义的类类型的名字,可以是任何有效标志符. BaseClass1,BaseClass2,… 可选,表示要继承的父类型,可以是 0 个、1 个或多个,如果是多个其中用逗号分割.如果此参数为空,可以省略 class 后面的小括号 memberList 声明类的各成员,也就是它的字段、方法和属性。可选. 注: 一个 Type …End;只能声明一个类类型; 即使 memberList 为空也不能省略 end; 完整示例: ```text Type Person = Class //字段 name; //方法 function SetName(newName); Begin name:=newName; end; // 方法 Function DisplayName(); begin writeln(name); end; //属性 Property theName read name write name; End; ``` 以上代码包括了一个完整类类型的声明: 声明了一个 Person 的类类型,也为 Person 类型声明了下面的成员: 字段:Name 方法:SetName 和 DisplayName 属性:theName #### 类类型声明的位置 与其他类型不同,类类型必须在实例化之前声明并给定一个名称。有三种地方可以声明类类型: 1、在程序(program)的最外层声明类,在执行语句块的前面,而不能在过程或函数中声明. 示例: ```text program test; //声明了一个名称为myClass的类类型 Type myClass = Class //这里可以定义类的成员:字段、方法、属性 End; Begin //这里可以初始化并使用上面声明的类类型 C:=CreateObject("myClass"); End. ``` 2、在主函数的后便声明,示例: ```text Function abcd(); Begin A:=CreateObject("myClass"); End; Type myClass = Class End; ``` 3、在非 Program 开头的 TSL 语句段后。 如: ```text ………….. A:=CreateObject("myClass"); ………… Type myClass = Class End; ``` 4、也可以在 "TSL 解释器安装目录\funcext\" 下面或者在其下的子目录下建立一个同名的.tsf 文件,在文件内部声明一个类类型,文件名和类名必须相同。 如:把 myClass 的类类型放在 myClass.tsf 文件中。这样可以被全局引用。 #### 类的实例化 创建一个类的实例对象,TSL 中提供了两种方式: 方式一:调用 CreateObject 函数进行创建; ```text CreateObject ([,P1,P2…]):TSLObject ``` 用类名字符串或者用一个类类型来创建一个类的对象,返回新建对象的引用。 方式二:使用 New 关键字方式进行创建: ```text New ClassName([P1,P2…]):TSLObject ``` 和 CreateObject 类似,但 ClassName 不再需要是一个字符串,而是直接写出类名即可,在类名后用(),括号里可以加入构造函数的参数。 注意:类名两端的括号不能省略,可使用字符串常量,也可以使用字符串变量。 也可以使用类类型作为对象的构造,类类型可以用 class(classname)以及 findclass 等来获得。 如果要创建类 Person 的实例,写法可以是以下两种方式: ```text Obj:=CreateObject('person'); obj:=new person(); ``` 如果类的构造器有参数,则需要把参数列表一起传给 CreateObject 函数,如给类 Person 的实例构造时指定两个属性: ```text Obj:=CreateObject('person',"zhangfei",25); obj:=new person("zhangfei",25); ``` 可以把对象的引用赋值给另外一个变量 Obj2 := Obj1; 这时 Obj2 和 Obj1 指向同一个实例,而不是 2 个实例。 #### 对象成员的访问 成员变量以及方法的访问 操作成员变量以及方法均采用.操作符。 例如: ```text Human:=New Person("张三"); Human.mSex:="男"; Human.mBirthday:=20120101T; Echo Human.GetAge(); ``` ##### 内容 - ?.模式访问 NIL 对象 ##### ?.模式访问 NIL 对象 如果某个内容本身可能是 NIL,也可能是对象,如果我们希望当 NIL 的时候访问方法或者成员不报错返回 NIL。 这个时候我们传统需要使用 a?a.b:nil,如果对象访问是嵌套的,例如 a.b.c,那么需要使用 a and a.b?a.b.c:nil,这种情况下使用?.模式会更为表达清晰。 TSL 支持使用 a?.b?.c 完成上述需求,该功能和 JAVASCRIPT 的?.相仿。同样的,我们也支持 a?.[index]模式访问,当 a 为 NIL 返回 NIL 具体可参考:?.模式 ### 类继承和作用域 #### 内容 - 继承 - 作用域 #### 继承 面向对象中,继承是基础。我们可以对已有的类复用和扩展。通过继承我们可以让新类拥有了已有类的数据和行为。也可以扩展新类,使它具有更多的数据和行为。 我们这里称已有类为新类的基类或父类,有的地方也叫超类。 我们称新类为已有类的子类或派生类。 由于 TSL 支持多级继承。其中基类,基类的基类(如果有的话)都统一叫做子类的祖先类。 子类可以通过继承获得基类的数据和方法,有效复用,提高开发效率,使代码易于维护。 TSL 继承的实现方式是:声明类类型时,在 Class 后面的括号内指定父类型的名称。TSL 支持多重继承,基类可以指定多个,其中用逗号分割。格式为: type myClass = class(BaseClass1[,BaseClass2,…]); 以上代码定义了一个叫做 myClass 的类,它继承自 BaseClass1、BaseClass2 列表。这样我们称 MyClass 为子类,BaseClass1,BaseClass2…为 MyClass 的基类或父类。也可以叫祖先类. 子类 MyClass 将获得基类(BaseClass1、BaseClass2、…)的所有非私有数据和行为,此外新类可以为自己定义新的数据和行为进行扩展,也可以重新定义基类中的行为. 示例: ```text Program test; //声明类A Type A = class Function F1() Begin Writeln("call A.F1"); End; End; ``` //声明类 B,继承自 A ```text Type B =Class(A) End; Begin //创建B类的实例对象BB BB:=CreateObject("B"); BB.F1; End. ``` 上面代码类 B 通过继承获得类 A 的方法 F1(),自己确不用定义方法 F1(); 如果子类的多个基类都有同样的方法,在子类中调用这个方法时需要为这个方法指定具体的父类,方法为在调用的方法前面加上 Class(基类名称). 示例 ```text Type Base1 =Class Function F(); Begin writeln("Base1.F"); End; End; Type Base2 =Class Function F(); Begin writeln("Base2.F"); End; End; Type SubClass =Class(Base1,Base2) Function CallBaseF(); Begin class(Base2).F();//指定要调用类Base2的F方法。 End; End; Begin S:=CreateObject("SubClass"); S.CallBaseF(); End. ``` 以上代码演示在类内部调用多个基类相同方法的方法,如果在子类的外部调用这个方法,总是调用基类声明在最前面的类的方法。没有办法调用其他基类的方法,一个技巧是必须在子类中包装这个方法,在外面调用包装的方法。 ##### 内容 - 继承单元类以及成员类 ##### 继承单元类以及成员类 ```text Type AA=class(UNITB.CC) //支持单元名.类名模式继承 .... End; ``` 同时也支持子类继承: ```text new AA(); Type AA=class(BB.CC) //CC是BB的成员类 FAA; End; type BB=class FBB; type cc=class FCC; function create(); begin echo "create"; end; end; end; ``` #### 作用域 类的每个成员都有一个称为可见性的属性,我们称为作用域。 作用域决定了一个成员在哪些地方以及如何能被访问。TSL 用下面 3 个关键字之一来表示它:private、protected、public Private:私有域内定义的成员变量以及方法以及其他均属于私有的,仅供在类成员方法中使用 即表示最小的访问能力,只能在类内部的方法、属性调用,不能从类的外部调用;也不能被继承。 Protected:相比 Private,子类可以引用,但外部不行 即表示中等的访问能力,在声明它的类的模块中是随处可用的,并且在它的派生类中也是可用的。 Public:公有域内定义的内容均可以被内外部调用 即表示最大的访问能力,只要能使用类的地方都是可用的。 注: 若声明一个成员时没有指定其作用域,则它和前面的成员拥有相同的作用域. 若在类声明的开始没有指定作用域, TSL 成员(包括字段、方法、属性)默认的作用域是 public。 作用域关键字可以在程序中重复出现多次。 为可读性考虑,最好在声明类时用作用域来组织成员:把所有的 private 成员组织在一起,接下来是所有的 protected 成员,最后是 public 成员。用这种方法,每个可见性关键字最多出现一次,并且标明了每个新段的开始。所以,一个典型的类声明应该像下面的形式: ```text type MyClass = class (BaseClass) private ... { private declarations here} protected ... { protected declarations here } public ... { public declarations here } end ; ``` 示例: 下面的代码详细说明了继承与作用域的关系 ```text program test; type A =class() private function F1(); Begin Writeln("from private F1"); End; protected Function F2(); Begin Writeln("from protected F2"); End; public Function F3(); Begin Writeln("from public F3"); End; Function F4(); Begin Writeln("from public F4"); F1();//正确,可以在类内部的方法调用private 的成员。 F2();//正确,可以在类内部的方法调用protected的成员 F3();//正确,可以在类内部的方法调用public的成员 End; End; Type B = Class(A) Function F5(); Begin Writeln(" Inherit test :call private funciton "); F1();//错误,不能调用基类的私有方法 End; Function F6(); Begin Writeln("inherit test: call protected function"); F2();//正确,调用基类的protected 方法 End; Function F7(); Begin Writeln("inhert test :call public function "); F3();//正确,调用基类的public 方法 End; End; Begin AA:=createobject("A"); AA.F1();//错误,不能调用类型的private方法 AA.F2();//错误,不能调用类型的protected方法 AA.F3();//正确,可以调用类型的public 方法 AA.F4();//正确,可以调用类型的public 方法,方法内部可以调用private成员. End. ``` ### 字段 #### 内容 - 字段简介 - static 静态字段 - const 常量成员 #### 字段简介 字段就像属于对象的一个变量,我们也称之为成员变量,它可以是任何类型。对象用户存放对象的数据。 给类定义字段非常简单,只要把字段的名字在类的声明中列出即可。定义方法: ```text Type myClass =Class Field1; Field2; End; ``` 以上的代码声明了一个 myClass 的类,同时定义了 2 个字段,Field1 和 Field2 引用: 1、在类内部的方法直接调用字段名 2、外部调用:实例对象.字段名,例如 ```text myObj:=CreateObject("myClass"); myObj.Field1:="This is a Field"; ``` 注: 可以为字段指定作用域 #### static 静态字段 在字段的前边加入 static 前缀,就表明为静态字段也称静态成员变量,静态字段就是全部类实例共用的字段,亦可以不用实例化来进行调用。 与对象实例无关,也就是所有对象实例均共用该变量,类似于一个作用域为该类的全局变量。 范例: ```text Type Thuman=class public static mCount;//人的对象数量,与对象无关 function create() begin mCount:=(mCount?:0)+1;//构造的时候+1 end; function destroy() begin //析构的时候-1 mCount--; end; End; ``` 调用方式可如: class(Thuman).mCount;//不用实例化来进行调用 或 obj:=new Thuman();//用实例化来进行调用 obj.mCount; #### const 常量成员 常量成员定义的值可以是一个常数也可以是常量参与的计算。具体定义与支持的运算符可参考常量及常量成员的定义与初始化 【常量成员定义】 ```text Type C=class Const a="Hello"; //可以在声明中进行定义初始化 Const b=a+"Tinysoft"; C=a+b+"from TSL"; End; ``` 【使用范围】 1、成员函数使用 2、成员函数缺省参数使用 3、子类使用 4、通过实例访问 5、通过类访问静态常量成员 示例: ```text Type C=class public const mA=1; //定义一个常量成员 static const mB=mA+10; //允许静态成员常量 function TestConst(); begin echo mA+mB,"\r\n"; //允许在成员函数中使用 end; function TestConstInParam(b=mB); //允许在缺省参数值中使用 begin echo b,"\r\n"; end; End; ``` 调用: ```text Cinstance:=New C(); Cinstance.TestConst(); Cinstance.TestConstInParam(); echo Cinstance.mA,"\r\n"; echo class(C).mB,"\r\n"; ``` 打印结果: 12 11 1 11 ### 方法 #### 内容 - 方法简介 - 声明和实现 - 覆盖(override) - 多态 - 隐藏 - 重载(overload) - 构造函数 - 析构函数 - 指定类 - Self - 类方法 #### 方法简介 方法定义一个类的行为,是一个和类相关联的函数,调用一个方法需指定它作用的对象(若是类方法,则指定类),比如, SomeObject.DoSomething 调用 SomeObject 的 DoSomething 方法。 #### 声明和实现 有 2 种方法为类添加方法。 在类声明中,可以直接定义方法的声明和实现, 或者只在类中定义方法的声明,在类声明后的某个地方(必须属于同一模块)定义它的实现,实现的时候在方法名称前加“类名.”。这种方法称为为外联,上一种方法称为内联. 示例: ```text Type myClass =class Function F1() ; Begin writeln("内联"); End; Function F2() ; End; function myClass.F2 (); Begin Writeln("外联"); End; ``` 外联声明时,方法名总是使用类名进行限定,形式为:类名.方法名。在方法的头部必须重新列出类声明时的参数,名称可以与声明时的不同,但是参数的顺序必须完全相同。 ##### 内容 - 内联与外联 - 静态方法声明和调用 - 对象的方法调用 ##### 内联与外联 如果函数的实现在类体内,叫内联方法。 如果函数的实现在类体外,叫外联方法。 示例: ```text Type TSamClass=Class Public Function MethodInside(); //内联方法--声名+实现 begin return "Inside"; end; function MethodOutSide();//仅声名 End; Function TSamClass.MethodOutSide(); //外联方法--具体实现 Begin return "outside"; End; ``` 外联声明时,方法名总是使用类名进行限定,形式为:类名.方法名。在方法的头部必须重新列出类声明时的参数,参数名称可以与声明时的不同,但是参数的顺序必须完全相同, ##### 静态方法声明和调用 静态方法与静态字段(静态成员变量) 所有静态方法就是与对象实例无关的方法,其定义为在函数的前边加上 class 前缀,也称类方法。类方法定义了类的行为,与类的实例无关。 而静态成员则是在变量的前边加上 static 前缀,表明该成员变量与对象实例无关,也就是所有对象实例均共用该变量,类似于一个作用域为该类的全局变量。 在静态方法中禁止使用类的非静态的成员变量。 类方法(静态方法)的声明: 声明类方法时 function 前面加 class.形式为:Class Function FunctionName([p1,p2,…)) 如果是外联实现,也在实现前面加 class,形式为:Class Function ClassName.FunctionName([p1,p2,…)) 类方法(静态方法)的调用: 在实例中的调用方法为: class(类名).方法名.形式为:Class(myClass).FunctionName([p1,p2,…]) 静态方法与静态成员范例 ```text Type Thuman=class public static mCount; //人的对象数量,与对象无关 class function getCount() ; //得到人对象的数量,与对象无关 begin return mCount; end; function create(); begin mCount:=(mCount?:0)+1;//构造的时候+1 end; function destroy(); begin //析构的时候-1 mCount--; end; End; ``` 静态方法与静态成员的访问 ```text class(Thuman).mCount:=100;//将Thuman类的静态字段mCount的值指定为100 echo class(Thuman).mCount;//输出静态字段mCount的值 hA:=new Thuman();//创建一个实例 echo class(Thuman).getCount();//调用静态方法 ``` 打印结果: 100 101 ##### 对象的方法调用 1、如果被类内部其他的方法调用或子类中的方法调用,直接调用方法名就可以了。 2、如果在类的外部被调用,需要加上所在类型的对象名:对象名.方法名; 如调用 F1()的方法是 ```text myObj:=createObject("myClass"); myObj.F1(); ``` 3、在类内部调用方法,若在父类中存在同名方法,默认是优先调用当前类, 若希望调用父类方法,则可使用 Inherited 关键字进行指定。 若希望调用指定父类方法,则可使用 class(父类名).方法名的模式调用。 ###### 内容 - Inherited ###### Inherited Inherited 是一种调用父类的巧妙的实现,这个实现和 Object pascal 遵循相同的规则。由于 tsl 支持多重继承,因而 Inherited 会优先调用第一个继承的父类,如果没找到则会遍历之后继承的类。 Inherited 和 java 的 super 有一定的类似之处,但又不相同, java 的 super 可以表达成父类,也可以调用父类的方法,而 Inherited 都是调用父类的方法,而且单独 Inheritd 的写法,在父类不存在方法的时候不会出错,这样的特性非常便于桌面应用开发里的子类窗口的消息事件响应。 用法有两种: 方式一:在方法中,增加 inherited;则表示执行父类中存在的与当前方法名同名同参数的方法,若父类中查找不到,不报错,即什么也不做,继续向下执行。 方式二:使用如 inherited func(a,b,c);的模式调用方法,表示调用父类中的该方法,若存在多父类,则按顺序查找,若父类中查找不到,则报错。 例如: ```text Type Base1 =Class Function Method1(s,a,b); virtual; Begin s:=s$"-Base1-Method1-"$(a+b); End; Function Method2(a,b); begin return "Base1-Method2-"$(a*b); end; End; Type SubClass =Class(Base1) Function Method1(s,a,b); override; Begin Inherited; //优先调用父类中Method1(s,a,b)方法,找不到不报错 s:=s+"->SubClass"; s2:= Inherited Method2(a,b);//指定调用父类中的Method2(a,b)方法,找不到会报错 s:=s+"->"+s2; return s; End; Function Method2(a,b); begin return "SubClass-Method2-"$(a/b); end; End; ``` 调用: ```text obj:=new SubClass(); return obj.Method1("S",2,50); ``` 返回结果为:S-Base1-Method1-52->SubClass->Base1-Method2-100 即:Inherited;语句执行父类 Base1 中同名同参数方法 Method1(s,a,b) Inherited Method2(a,b);执行父类 Base1 中指定方法 Method2,而非当前类 SubClass 的 Method2 方法 #### 覆盖(override) 由于继承,子类具有了父类全部非私有的成员(字段、方法、属性),但是子类也可以对基类的方法进行重写。这种方法就叫做覆盖(override),具体的做法如下, 首先基类的方法用 virtual 关键字虚函数,告诉编译器允许子类覆盖: ```text Type BaseClass =class Funciton F(); virtual; //虚方法,允许覆盖 Begin //… End; End ``` 接下来,在子类中将将要覆盖的方法用 override 关键字标记为覆盖了基类的方法。它的参数的顺序(若有的话)必须和基类相同。 ```text Type SubClass =class(BaseClass) Funciton F(); override; //覆盖虚方法,即重写 Begin //… End; End ``` 这样子类的方法 F 就覆盖了基类的方法 F,当 SubClass 的实例调用 F 方法时,会执行子类中重新定义的方法。 若需要调用父类被覆盖的方法,可以用 Class(父类).方法来调用 #### 多态 多态是面向对象的重要特性,简单点说:“一个接口,多种实现”,就是同一种事物表现出的多种形态。 编程其实就是一个将具体世界进行抽象化的过程,多态就是抽象化的一种体现,把一系列具体事物的共同点抽象出来, 再通过这个抽象的事物, 与不同的具体事物进行对话。 通过继承可以实现多态。父类中调用被覆盖的方法,如果当前对象是子类的实例,那么实际调用的是子类的方法,而非父类的方法。 通过继承,一个类可以用作多种类型:可以用作它自己的类型、任何祖先类型,当把子类型当作祖先类型时,调用被覆盖的方法,实际调用的是子类本身的方法,而非基类型的方法。 示例: ```text program test; type Figure = class Function Draw(); virtual; //虚方法,可以被覆盖 Begin Writeln("draw Figure"); End; Function DrawAction(); Begin Draw(); End; End; Type Ellipse = class(Figure) Function Draw(); override; //重写父类方法 Begin Writeln("draw Ellipse"); End; end; Begin F:=CreateObject("Figure"); F.DrawAction();//输出 draw Figure E:=CreateObject("Ellipse"); E.DrawAction();//输出 draw Ellipse End. ``` 上面的示例中: 类 Ellipse 的方法 Draw,重写了父类 Draw 这个虚方法,父类的 DrawAction 调用了 Draw 方法,当对象调用 DrawAction 方法时,实际上是间接调用了 Draw 方法。 当父类的对象间接 Draw 方法时:执行的是父类的方法。 ```text F:=CreateObject("Figure"); F.DrawAction();//输出 draw Figure ``` 当子类的对象间接用 Draw 方法时:执行的是子类的方法: ```text E:=CreateObject("Ellipse"); E.DrawAction();//输出 draw Ellipse ``` 如果要强制子类调用父类的方法。需要用下面的方式: ```text Class(BaseClass,SubObject).FunctionName. ``` 上面的事例中, ```text E:=CreateObject("Ellipse"); Class(Figure,E).Draw() ; ``` 执行的却是父类的 Draw 方法.输出:输出 draw Figure #### 隐藏 如果在子类中重写父类的方法确没有使用 override 标志符,子类的方法隐藏了基类的方法,而非覆盖。 父类中调用覆盖的方法时,实际执行的是父类的方法。如果当前对象是子类的实例时,执行的还是父类的方法。因为方法在子类型中给隐藏了,而没有被覆盖。 示例: ```text program test; type Figure = class Function Draw(); Begin Writeln("draw Figure"); End; Function DrawAction(); Begin Draw(); End; End; Type Ellipse = class(Figure) Function Draw();// 注意没有override Begin Writeln("draw Ellipse"); End; end; Begin F:=CreateObject("Figure"); F.DrawAction();//输出draw Figure E:=CreateObject("Ellipse"); E.DrawAction();//输出draw Figure End. ``` 与上节的例子不同,子类中定义 Draw 方法没有使用 override 关键字,说明子类的 Draw 方法隐藏了父类的 Draw 方法. 在父类在中调用 Draw 方法时,始终执行的是父类的 Draw 方法. #### 重载(overload) TSL 可以为一个类声明相同的名称不同参数的多个方法,这叫做重载。 每个重载方法声明后面加关键字 overload,并且它们必须有不同的参数列表。 形式为: ```text Function F();overload; ``` 示例: ```text Type BaseClass =class public function Display(str,str2) ;overload; Begin writeln(str,' ',str2); End; function Display(str); overload; begin writeln(str); end; End; ``` 上面的代码为 BaseClass 声明了 2 个 Display 方法。可以按照 2 种方式调用,可以在子类中重载也可以重载父类的方法。 示例: ```text program test; Type BaseClass =class public function Display(str); begin writeln(str); end; End; Type SubClass =class(BaseClass) function Display(str,str2);overload; Begin writeln(str,' ',str2); End; End; Begin SC:=createObject("SubClass"); SC.Display("overload"); SC.Display("overload","test"); End. ``` 上面的例子中 SubClass 继承自 BaseClass,而 SubClass 的 Display 方法重载了父类 Display 方法。 原理:SubClass 通过继承实际上拥有了方法 Display(str)方法,然后通过 overload 重载了本身的方法,于是 SubClass 具有了 2 个不同参数的 Display 方法。 #### 构造函数 构造函数是一个特殊的方法,用来创建和初始化一个实例对象。 声明一个构造函数就像声明一个函数一样,可以无参数也可以有参数,不同的是方法名必须是 create,在创建实例时会自动查找适合的构造函数。 Function Create() TSL 总是为一个类生成默认的公有(public)的 create 方法, 如果显式没有为类声明 public create,对象初始化时就使用默认的 create 方法,如果用户声明了 public create 方法,对象初始化时就执行用户定义的方法。Create 不可以声明为私有(private)的和受保护(protected)的方法,否则对象初始化时不执行自己声明的方法. Create 方法可以被重载(overload)几个不同的定义。 由于使用 CreateObject 方法创建对象,Craete 方法的返回值将被忽略。 示例: 示例是一个简单的日历类,说明了构造函数的重载,初始化时如果调用 Create 方法,设置为当前日期,否则可以指定具体的年月日 ```text program test; Type Calandar =Class year; month; day; function Create() ;overload; Begin Create(YearOf(Date()),MonthOf(Date()),DayOf(Date())); End; function Create(y,m,d);overload; Begin year:=y; month:=m; day:=d; End; End; Begin C:=CreateObject("Calandar"); //C:=CreateObject("Calandar",2008,8,8);也可以指定具体的年月日 writeln(C.year,C.Month,C.Day); End. ``` 构造函数的覆盖: 构造函数可以在子类中被覆盖,如果显示声明了构造函数,为了是成员初始化,一般在新的构造函数中都要求实现基类的构造函数 调用 Class(BaseClass).Create(); #### 析构函数 对象销毁时候执行的方法。声明一个析构函数就像声明一个一般的函数,必须以关键字 Destroy 命名的函数,且无参数,当对象释放时会自动调用。 Function destroy(); #### 指定类 如果要指定执行某个类中的方法,需要用 Class 指定类名。 如果在类的内部,或者执行类方法,格式为: Class(ClassName).FunctionName; 表示执行类 ClassName 中的方法 FunctionName; 如果是对实例对象,希望实例对象执行某个祖先类的方法,格式为: Class(ClassName,ObjectName).FunctionName; 表示实例对象 ObjectName 执行祖先类 ClassName 的 FunctionName 方法。 #### Self 在面向对象中,self 有多种用途: 第一种:在指定方法时,可以通过 self 指向当前的实例对象。 第二种:self(N)方式,可以在类中创建当前类对象或创建实例所属对象。 第一种用途: 在实现方法时,标志符 Self 引用方法所属的对象,如果是类方法,Self 引用方法所属的类。 格式为: Self.functionName(); 编译器会自动匹配所调用的方法,Self 方法一般可以省略。 有一点注意的是: Self 总是指向当前的实例对象。而不是 Self 所在的类的实例对象。与继承混合使用是需要注意。 示例: ```text Program test; type A= class Function F(); virtual; Begin Self.F2(); End; Function F2();virtual; Begin Writeln("A.F2"); End; End; Type B = class(A) Function F2();override; Begin Writeln("B.F2"); End; end; Begin AA:=CreateObject("A"); AA.F();//输出 A.F2; BB:=CreateObject("B"); BB.F();//输出 B.F2() End. ``` 说明: AA:=CreateObject("A"); AA.F();//输出 A.F2; 创建了类型 A 的实例对象,F()中的 Self.F2(),表示调用的是类型 A 的 F2(); BB:=CreateObject("B"); BB.F();//输出 B.F2() 以上代码创建了类型 B 的实例对象,F()中的 Self.F2()表示调用类型 B 的 F2() Self 的这种特性在某些情况下会出现理解上的歧义,如果想固定 Self 的意义,让他只表示当前的类。需要用 Class(ClassName).FunctionName 做替换。 以上代码中的 Self.F2()需要换成 Class(A).F2(); 那么以上代码输出 A.F2 A.F2 第二种用途: 在实现方法时,可以通过 self(1)创建一个当前实例所属对象的实例对象。 self(0)等同于 self()即创建一个当前方法所在类的实例对象。 如: ```text Function Test_Ooself(); Begin obj:=CreateObject('TestSelf'); obj.Test1(); End; Type TestSelf=class(TDTestFClass) Function Test1(); begin returnV1(); returnV0(); end end; Type TDTestFClass=class() Public Function returnV1(); Begin ss:=self(1); //创建当前实例所属类的实例对象 echo "TDTestFClass-returnV1 ", ss.classinfo()['classname']; End; Function returnV0(); Begin ss:=self(0); //创建当前类的对象 echo "TDTestFClass-returnV0 ", ss.classinfo()['classname']; End; End; ``` 打印结果如下: TDTestFClass-returnV1 testself TDTestFClass-returnV0 tdtestfclass 注:示例中 ss.classinfo()['classname'];是获取 ss 所属对象的类名 #### 类方法 类方法是作用在类而不是对象上面的方法(不同于构造函数)。类方法的定义必须以关键字 class 开始 类方法用于创建无需创建类的实例就能够访问的方法。类方法可用于分离独立于任何对象标识的行为:无论对象发生什么更改,这些函数都不会随之变化。 形式为: ```text Type ClassName =Class Class Function FuncName(); Begin //方法实现 End; End ``` 在类方法的定义部分,Self 表示调用方法的类(它或许是定义方法的类的一个派生类)。由于类方法与实例对象无关,所以,你不能使用 Self 访问字段、属性和实例的方法,但能调用构造函数和其它类方法。 类方法可以通过类引用来调用 Class(类名).类方法 示例: 上例中,可以 Class(ClassName).FuncName(); 注: 一个类方法也可以被当作实例方法使用,使用方法和实例方法完全一样。方法的内部也可以调用实例的字段、属性和方法,如果方法调用了这样的数据或方法,就不能当作类方法使用了,否则的话会出错。 在 Tsl 中,字段和属性不支持这种静态的属性方法. 静态的字段可以通过全局变量实现。 更多可参考:静态方法声明和调用 ### 属性 Property 属性是这样的成员:它们提供灵活的机制来读取、编写或计算私有字段的值。可以像使用公共数据成员一样使用属性,但实际上它们是称作“访问器”的特殊方法。这使得可以轻松访问数据,此外还有助于提高方法的安全性和灵活性。 语法:Property PropertyName[(ParamList)] [read fieldOrMethod][write fieldOrMethod][Index IndexValue] 其中, 1、关键字 Property 关键字表示开始声明了一个属性; 2、PropertyName 是自定义合法的属性名,可以带参数,写法如 PropertyName(a,b); 3、每个属性至少有一个读限定符或一个写限定符,或两者都有,它们称为访问限定符,具有以下的格式: read fieldOrMethod write fieldOrMethod fieldOrMethod 可以是成员变量,也可以是成员方法。 4、在 TSL.INI 支持,一旦设定该选项为 1,则任何域的 property 都可被访问,无论是 public 还是 protected,private。默认情况下这种违反规则是不被允许的。 [Compatible] PrivatePropertyAccess=1 5、属性可以具有 Private,Protected 或 public 可见性,默认为 public. 6、如果单有读限定符,表示属性只读;如果单有写限定符,表示属性只写。 7、如果它是在祖先类中声明的,则它对派生类必须是可见的,则 fieldOrMethod 不能是私有的字段或方法; 8、在读限定符中,若 fieldOrMethod 是一个方法,它须是一个小于等于定义中参数数量的函数 9、在写限定符中,若 fieldOrMethod 是一个方法,属性的设置值会以参数方式送入成员方法,即它须是一个与定义中参数数量多一个的方法。 10、属性可以在派生类中给重新定义. 示例: ```text program test; Type myDate = Class private _year; _month; _day; Function SetMonth(value); Begin if value>0 and value<13 then _month:=value; End; public //不带参数的定义 property Month read _month write setMonth;//读时访问成员变量_month,写时调用成员方法setMonth //带参数的定义 property DateV(y,m) read getDateV write setDateV; Function getDateV(); begin return _year*10000+_month*100+_day; end; Function setDateV(y,m,d); //比定义中多一个参数 begin _year:=y; SetMonth(m); _day:=d; end; End; Begin D:=CreateObject("myDate"); D.Month:=7; //写 echo D.Month;//读 D.DateV(2025,8):=10;//写 echo D.DateV();//读 End. ``` 打印结果: 7 20250810 ### 索引器(index) 简单说来,所谓索引器就是一类特殊的属性,通过它们你就可以像引用数组一样引用自己的对象。索引器通常用于对象容器中为其内的对象提供友好的存取界面. 显然,这一功能在创建集合类的场合特别有用,而在其他某些情况下,比如处理大型文件或者抽象某些有限资源等,能让类具有类似数组的行为当然也是非常有用的。 索引器的定义方式为: Property PropertyName Index IndexValue read ReadMethod write WriteMethod 与属性不同的是,其中读写限定符必须是方法,不能是字段。而且 读限定符中的方法声明必须带有一个参数,这个参数指向索引器的索引。 写限定符的方法声明必须带有 2 个参数,第一个参数是索引器的索引,第二个是要设置的值。 与数组的区别,调用索引器的时候用圆括号,不能用方括号。 与 Object pascal 不同的地方:TSL 的索引器的索引值除了支持整数以外,还可以支持字符串。 实例: ```text program test; type A=class() arr; function create() Begin arr:=array(); End; function rIndex(i); Begin return arr[i]; End; function wIndex(i,value); Begin arr[i]:=value; End; property idx read rindex write windex; End; begin AA:=createobject("A"); AA.idx(0):="abc"; writeln(AA.idx(0)); End. ``` 上面的示例演示了索引器的使用方法。对类 A 的数据 arr 的操作,不必通过对象 AA.arr 来设置或读取,只要通过索引器即可。索引器为 A 中的数据提供友好的存取界面。 我们可以把索引器的一个索引固定为属性,就需要下面的定义方法: Property PropertyName Index IndexValue read ReadMethod write WriteMethod 用 index n 指定索引的位置 上例中可声明 ```text property idx0 index 0 read rindex write windex; ``` 表示 idx0 表示专门对索引器中的位置 0 进行对写,也就是对 arr[0]进行操作。 当然,假使有需要,索引也可以使字符串,那样,例如: ```text property idx0 index "High school" read rindex write windex; ``` ### TSL 对象的创建 #### 内容 - New - CreateObject #### New 参考 TSL 内置对象使用大全 CreateObject #### CreateObject 参考 TSL 内置对象使用大全 New ### 类信息 判定一个对象是否是某个类的实例,可以用 is 判断符。 Class(类名)或者 FindClass(类名字符串)可以获得一个类的类型。 CreateObject 支持通过指定类的类型创建实例。 如: ```text obj1:=New T1(); Echo obj1 is class(T1) ; //判断对象是否是指定类的实例 C1:= findclass("t1") ;//获取指定类的类型 Echo obj1 is C1 ; obj2:= CreateObject(C1) ;//通过指定类的类型创建实例 ``` #### 内容 - FindClass - ClassInfo - objectstate - tslassigning - 对象的引用计数 #### FindClass 范例 范例 01:通过查找类运行类方法 示例: classA :=FindClass("A"); classA 指向了类 A,可以通过 ClassA 调用 A 的共享方法。但是不能调用实例方法,因为 ClassA 没有指向实例对象。 ```text //有类: Type ClassA=class() class function fucA(); begin return "ClassA"; end; end; //调用: return findclass("ClassA").fucA(); ``` 返回:ClassA 范例 02:将实例对象强制转成指定父类的实例 ```text //有父类: Type ClassA=class() function fuc();virtual; begin return "ClassA"; end; end; //有子类: Type ClassB=class(ClassA) function fuc();virtual; begin return "ClassB"; end; end; //调用: objb:=new ClassB(); obj:= findclass("ClassA",objb);//将objb对象强制转换成ClassA的实例对象 return obj.fuc(); ``` 返回:ClassA #### ClassInfo 范例 范例 1:返回当前实例对象所属类的定义信息 ```text obj:=createobject("TSBackTesting"); return obj.classinfo(); ``` 范例 2:返回实例对象所属类的对象类型。 ```text obj:=createobject("TSBackTesting"); oa2:=obj.classinfo(1); //oa2是一个类的类型 obj2:= createobject(oa2); //通过类类型构造一个实例对象 return obj2.fbegt; ``` #### objectstate 范例 ```text oa := new ca("abc"); echo "\r\n构造已经完成",objectstate(oa); type ca = class static sca; function create(n); begin sca := self; echo "\r\n构造中:", objectstate(self) ; end end ``` 打印结果: 构造中:1 构造已经完成 2 #### tslassigning 如在给属性的赋值方法中打印这个状态值 ```text o := new ca(); o.c := 3; //给对象的属性赋值 return o.c; type ca = class value; property c read getc write setc; function setc(v); //对象赋值中 begin echo "c的写操作>",tslassigning,"<<<<"; value:=v; end function getc(); begin echo "c的读操作>",tslassigning,"<<<<"; return value; end end ``` 打印结果: c 的写操作>1<<<< c 的读操作>0<<<< #### 对象的引用计数 A:对象的赋值均会将对象的引用计数加 1,当引用计数为 0 的时候才会释放。 ```text O1:=New T1(); //创建对象,引用计数=1 O2:=O1; //对象引用计数加1 O1:=0; //对象引用计数减1 echo "O1 to Zero"; O2:=0; //对象引用计算减1,为0,即释放对象 echo "O2 to Zero"; Type T1=class function destroy(); begin echo "destroy"; end; End; ``` ### IS 关键字 关键字 IS 用户判断一个对象是否是某个类的实例。返回值为 Bool 类型。一个子类属于所有它祖先类的类型。 示例: ```text program test; Type A=Class End; Type B =Class(A) End; Type C=Class(B) End Begin CC:=CreateObject("C"); Writeln(CC is Class(C)); // 输出 1 Writeln(CC is Class(A)); // 输出 1 Writeln(CC is Class(B));// 输出 1 End. ``` ### 函数信息 #### 内容 - FindOverLoad - TSLObjects - FindFunction - ThisFunction - FunctionInfo #### FindOverLoad 范例 ```text Type TestClass=class function fun(p1,p2);overload; begin return p1+p2; end function fun(p1);overload; begin return 'a'; end class function fun2(p1,p2); begin return p1+p2; end end; //调用有两个参数的重载方法 t:=findoverload(2,"fun",CreateObject('TestClass')); return t.do(1,2);//返回3 ``` #### TSLObjects 范例 现有类 TestClass01,其代码如下: ```text type TestClass01=class() value; function create(_value) begin value:=_value; end class function add(x,y) begin if ifnumber(x) and ifnumber(y) then return x+y; else return 0; end end ``` 范例 01:获取当前运行环境下所有对象的引用计数信息 ```text //创建对象,初始引用个数均为1 objA:=new TestClass01(100);//objA-直接引用:1,间接引用:1 //将对象赋值给其它变量,增加objA的直接引用数 objC:=objA;//objA-直接引用:2,间接引用:1 objB:=new TestClass01(101);//objB-直接引用:1,间接引用:1 //通过对象查找类中的方法,增加objB的间接引用 funcA:=findfunction("add",objB);//objB-直接引用:1,间接引用:2 funcB:=findfunction("add",objB);//objB-直接引用:1,间接引用:3 //通过类名查找类中的方法,没有引用对象,已有对象引用数不变 funcC:=findfunction("add",class(TestClass01)); return TSLObjects(0); ``` //结果: 范例 02:获取当前运行环境下所有对象信息以及原对象,并通过该结果访问其属性、方法 ```text objA:=new TestClass01(100); objB:=new TestClass01(101); objsInfo:=TSLObjects(1); newObjA:=objsInfo["TestClass01"][1,"obj"]; newObjB:=objsInfo["TestClass01"][0,"obj"]; //获取到的对象,其属性和方法与先前直接创建出的对象一致 v1:=newObjA.value; v2:=newObjB.value; t1:=newObjA.add(1,2); t2:=newObjB.add(3,4); return array(v1,v2,t1,t2); ``` //结果: #### FindFunction 在对象或类中查找方法: F:=FindFunction(FunctionName, Object or Class) 表示在 Object 对象或 Class 中查找名称为 FunctionName 的函数。F 指向找到的函数。 第二个参数可以是 1)对象,必须预先实例化一个对象,之中方法可以用于查找实例方法或类方法。 2)类,格式为:Class(类名)。这种方法只能差找类方法,不能查找实例方法 找到的函数可以用 do 方法执行; F.do();表示执行找到的方法,如果函数有参数,把参数传给 do 方法 program test; type A=class() function F() Begin writeln("f"); End; class function F2(); Begin writeln("f2"); end; End; begin //从对象中查找实例方法 AA:=createobject("A"); F:=FindFunction("F",AA); F.do(); //从类中查找类方法 F2:=FindFunction("F2",class(A)); F2.do(); End. #### ThisFunction F:=ThisFunction(Object or class.Function); 查找方法的又一个方法;参数格式为: 1. 对象名.方法名,如果创建了对象,可用这种方法。 2. class(类名).方法名,如果是类方法,而且没有穿件对象,可以这样使用。 program test; type A=class() function F() Begin writeln("f"); End; class function F2(); Begin writeln("f2"); end; End; begin //从对象中查找实例方法 AA:=createobject("A"); F:=ThisFunction(AA.F); F.do(); //从类中查找类方法 F2:=ThisFunction(class(A).F2); F2.do(); End. #### FunctionInfo 调用方法: 方法.FunctionInfo 获取函数的信息。返回存放函数信息的字符串下标数组。
下标 数据类型 描述
functionname String 方法名
parameter Array 方法参数
returntype Stirng 函数返回值
returndim Integer 数组的维度,0表示不是数组
calltype Integer 调用类型
classname Stirng 所在的类名
其中:parameter 下标所对应的数组也是字符串下标数组。 下标
下标 数据类型 描述
nme String 参数名称
tpe String 参数类型
dm Integer 数组的维度
out Integer
注意: 可以显式为参数或返回值定义类型。当定显式义了类型后以上提到的数据类型将会是自定义定义的值,否则是空字符串,这种用法不会真正做类型检查或转化,只是通知 FunctionInfo 中的数据类型,通常用户 Web service 的构建。 ### 算符重载 TSL 的对象如果要使用算符进行计算,就需要用到算符重载,算符重载可以重载掉 TSL 的算符,在 TSL 的类中要实现算符重载的方法。 算符重载支持 TSL 开发的类,也支持用 C++等开发的二进制类。 #### 内容 - Operator - 算符重载的案例 - 面向对象的 Operator 重载支持[] - 面向对象的 Operator 算符重载支持++,--,+=,-= #### Operator #### 算符重载的案例 下边是一个复数的例子,范例中重载了+和<运算符: ```text Type Tcomplex=class vReal;//实部 vImaginary;//虚部 function Operator +(data); //单参数,即只支持obj+10,不支持10+obj begin r:=new Tcomplex(); if ifnumber(data) then r.vReal:=vReal+data else begin r.vReal:=vReal+data.vReal; r.vImaginary:=vImaginary+data. vImaginary; end; return r; end; function Operator<(data,isLeft); //双参数,支持obj<10的判断,也支持10",index,"->",v; data[index]:=v; end; end; ``` 调用测试如: ```text t:=array(1,2,3,4,5); b:=new bb(t); a:=b[2];//取值 echo "b[2]:",a; b[3]:=999; //重新赋值 echo "b.data:",tostn(b.data); ``` 打印如下: b[2]:3 set->3->999 b.data: array(1,2,3,999,5) ##### 内容 - 对象[]重载时允许多级的应用示例 - 对象算符重载数组 set 算符时 none 类型的应用实例 ##### 对象[]重载时允许多级的应用示例 示例:对象中[]算符重载多级的实现示例 ```text type aa=class data; indList; public function create(v); begin data:=v; indList:=array(); end; function operator0; //多级访问 begin //s1<0时,最后一层 indList[length(indList)]:=index; v:=data; for i,ind in indList do v:=v[ind]; if s1<0 then begin indList:=array(); return v; end else return self; //返回对象 end; function operator1; begin indList[length(indList)]:=index; if ifnone(v) then return self; //返回对象,存在多级 sv:='data'; for i,ind in indList do if ifstring(ind) then sv+="['"+ind+"']"; else sv+="["$ind$"]"; sv+=":=v;"; eval(&sv); indList:=array(); end; end; ``` 调用测试: ```text t:=array(("A":1,"B":2,"C":3),("A":11,"B":22,"C":33)); a:=new aa(t); echo a[0,"B"]; a[1,"C"]:=999; echo tostn(a.data); ``` 打印结果: 2 array( ("A":1,"B":2,"C":3), ("A":11,"B":22,"C":999)) ##### 对象算符重载数组 set 算符时 none 类型的应用实例 例如,实现一个资金流入流出的账单记录,当对历史记录进行篡改时,会引发赋值出错,进行数据回滚处理。如此来展示对象算符重载数组 set 算符时,ifnone(v,i)等功能的作用 ```text //资金出入的联动实现,行标下只能依次递增,否则报错回滚 Type DepositMoney = class() FMoneyMX; FlastR; //上行 FnewR; //当前行 function create(v); begin FMoneyMX:=array(); FMoneyMX[0]["时间"] := datetimetostr(now());//初始资产 FMoneyMX[0]["当前余额"] := v;//初始资产 FMoneyMX[0]["出金"] := 0;// FMoneyMX[0]["入金"] := 0;// FlastR:=-1; FnewR:=0; end function operator1; //设置值 begin // echo "Idx->",idx," v->",v; //当赋值出错时,进入该过程,进行回滚 if ifnone(v,-1) then //none类型,且none整数位为-1 begin //回滚到上一次的状态 FMoneyMX:=FMoneyMX[0:FlastR]; FnewR:=FlastR; FlastR:=FlastR-1; echo "发生错误-回滚到变更前状态:",tostn(FMoneyMX); return "Erro"; end; if ifnone(v) then //中间层级 begin // echo "getnone(v)->",getnone(v);//当前级别 if getnone(v)=0 then begin //第一层 FlastR:=FnewR; FnewR:=idx; FMoneyMX[idx,"时间"]:=datetimetostr(now()); if FnewR",tostn(obj.FMoneyMX); sleep(1*1000); obj[2]["出金"]:=200; echo "出金200->",tostn(obj.FMoneyMX); sleep(1*1000); obj[2]["出金"]:=100; //此时变动下标应该是3,指定2会引发set出现,数据会进行回滚 echo "出金100->",tostn(obj.FMoneyMX); return obj.FMoneyMX; ``` 执行报错后,打印结果如下:(在 obj[2]["出金"]:=100;时触发出错逻辑,数据回到赋值之前的状态) 入金 888-> array( ("时间":"2025-08-12 17:55:40","当前余额":100,"出金":0,"入金":0), ("时间":"2025-08-12 17:55:41","当前余额":988,"出金":0,"入金":888)) 出金 200-> array( ("时间":"2025-08-12 17:55:40","当前余额":100,"出金":0,"入金":0), ("时间":"2025-08-12 17:55:41","当前余额":988,"出金":0,"入金":888), ("时间":"2025-08-12 17:55:42","当前余额":788,"出金":200,"入金":0)) 出金 100-> 发生错误-回滚到变更前状态: array( ("时间":"2025-08-12 17:55:40","当前余额":100,"出金":0,"入金":0), ("时间":"2025-08-12 17:55:41","当前余额":988,"出金":0,"入金":888), ("时间":"2025-08-12 17:55:43","当前余额":788,"出金":200,"入金":0)) #### 面向对象的 Operator 算符重载支持++,--,+=,-= 实现示例如: ```text type bb=class data; public function create(v); begin data:=v; end; function operator++(v); begin if v=0 then//d:=obj++;时 begin r:= new bb(); r.data:=data; r.data++; return r; end //其它情况下,都是++后的状态 else data++; end; function operator--(v); begin if v=0 then begin r:= new bb(); r.data:=data; r.data--; return r; end else data--; end; function operator+=(v); begin data+=v; end; function operator-=(v); begin data-=v; end; end; ``` 调用测试: ```text t:=array(1,2,3,999,5); b:=new bb(t); ++b;//自加 echo "++b后:"; echo "b.data: ",tostn(b.data); c:=b++; echo "c:=b++;后:"; echo "c.data: ",tostn(c.data); echo "b.data:",tostn(b.data); ``` 打印结果如下: ++b 后: b.data: array(2,3,4,1000,6) c:=b++;后: c.data: array(2,3,4,1000,6) b.data: array(3,4,5,1001,7) ### 单元中的类 天软中,可以将相同功能封装到单元中,形成专用工具方法库。 在单元中的类,可通过 obj:=new Unit1.Class1.Class2()的方式进行构建 通过 Type ClassA=Class(Unit1.Class1.Class2...)模式进行继承 #### 内容 - 继承单元中的类 - 构造单元中的类实例 - 预定义:ParentClassInUnit - 单元中的类-应用实例 #### 继承单元中的类 继承单元中的类,和继承常规类不同: 继承常规类:直接继承一个已知的类,如 Type ClassA=Class(TStringList)。 继承单元中的类:需要通过 Type ClassA=Class(Unit1.Class1.Class2...)模式来定义类,Class 中包含“单元名.外层类名.内层类名”的完整路径形式,精确指定要继承的类位置。 具体语法如下: Type ClassA=Class(Unit1.Class1.Class2[,OtherClass...]) 例如 Type ClassA = Class(Unit1.Class1.Class2),表示 ClassA 将直接继承单元 Unit1 中 Class1 内部定义的嵌套类 Class2。 书写时需注意,必须完整、准确的指定从单元名到最终类名的全部路径,否则会执行失败。 注:2025-08-27 后的 NG 客户端及使用新一代 TSL 的服务器支持该功能。 示例: 定义于 Unit1 中的类结构 ```text Unit Unit1; Interface Type Class1=Class Type Class2=Class// 嵌套类 function MethodInClass2();//方法 class function ClassMethodInClass2();//类方法 end; end; Initialization Finalization End. ``` 直接继承 Unit1.Class1.Class2 ```text Type MyNewClass = Class(Unit1.Class1.Class2) function MyNewMethod(); end; ``` 创建实例 ```text //方式一:CreateObject obj1:=CreateObject("MyNewClass"); obj1.MethodInClass2();//调用父类方法 //方式二:new关键字 obj2:=new MyNewClass(); obj2.MethodInClass2();//调用父类方法 ``` 查找类 ```text classRef:=FindClass("MyNewClass"); classRef.ClassMethodInClass2();//调用父类中类方法 ``` #### 构造单元中的类实例 构造单元中的类实例与构造常规类实例方法类似,均可使用 CreateObject 或 new 实现。 核心区别在于类标识符的指定方式: 常规类实例:只需提供类名,如 CreateObject("TStringList")或 new TStringList()。 单元中的类实例:需提供完整的类路径(格式:单元名.类名),如 CreateObject("Unit1.Class1.Class2")或 new Unit1.Class1.Class2()。 具体语法如下: obj:=CreateObject("Unit1.Class1.Class2"[,P1,...,PN:any]);//CreateObject 方式 obj:=new Unit1.Class1.Class2([,P1,...,PN:any]);//new 方式 例如 obj:= new Unit1.Class1.Class2(),表示创建单元 Unit1 中 Class1 内部定义的嵌套类 Class2 的实例,并赋值给 obj。 注:2025-08-27 后的 NG 客户端及使用新一代 TSL 的服务器支持该功能。 示例: 定义于 Unit1 中的类结构 ```text Unit Unit1; Interface Type Class1=Class Type Class2=Class// 嵌套类 function MethodInClass2();//方法 class function ClassMethodInClass2();//类方法 end; end; Initialization Finalization End. ``` 创建实例 ```text //方式一:CreateObject obj1:=CreateObject("Unit1.Class1.Class2"); obj1.MethodInClass2();//调用方法 //方式二:new关键字 obj2:=new Unit1.Class1.Class2(); obj2.MethodInClass2();//调用方法 ``` #### 预定义:ParentClassInUnit 判定当前环境是否支持继承和构造单元中的类 ```text {$IFDEF ParentClassInUnit} return 1; {$ELSE} //否则(如果未定义) return "当前环境不支持继承和构造单元中的类"; {$ENDIF} ``` #### 单元中的类-应用实例 现有日期相关单元 TD_DateUnit,单元中包含类 TD_DateClass、IntDate、StrDate。 ```text Unit TD_DateUnit; Interface Type TD_DateClass=class()//父类 value; //天软日期 Function create(v); begin value := isDate(v)?v:0; end; function isDate();overload; begin return isDate(value); end class Function isDate(v);overload; //是否是一个日期 begin try y := yearof(v); m := monthof(v); d := dayof(v); return isValidDate(y,m,d); except return 0; end; end; //--整型-日期 Type IntDate=class(TD_DateClass)//内部类,继承父类 iDate;//对应的整数日期 Function create(v); begin iDate:=_datetoint(v); value:=inttodate(iDate); end; function _datetoint();overload; begin return iDate; end class Function _datetoint(v);overload; begin if ifstring(v)then begin _iDate := datetoint(strtodate(v)); end else if v<99999 then begin isd := isDate(v); _iDate := isd?datetoint(v):v; end else _iDate:=Int(v); return _iDate; end end; //--字符串-日期 Type StrDate=class()//内部类,不继承父类 value;//天软日期 sDate;//对应的字符串日期 Function create(v); begin sDate:=_datetostr(v); value:=strtodate(sDate); end; class Function _datetostr(v) begin obj := new IntDate(v); _sDate := datetostr(obj.value); return _sDate; end Function formatS(f); //按指定符号生成字符串日期 begin fs := "yyyy"+f+"mm"+f+"dd"; return FormatDateTime(fs,value); end; end; End; Implementation Initialization Finalization End. ``` 使用示例 ```text dateClass:=findclass("TD_DateUnit.TD_DateClass"); echo dateClass.isDate(20250912T);//天软日期,返回值:1 echo dateClass.isDate("2025-09-12");//字符串日期,返回值:0 //现有如下日期 endt:=20250912T; //通过intDate类,转换成整数日期 obj:=new TD_DateUnit.TD_DateClass.intDate(endt); echo obj.iDate;//返回值:20250912 echo obj._datetoint("2025-09-12");//返回值:20250912 //通过strDate类,转换成整数日期 obj:=new TD_DateUnit.TD_DateClass.strDate(endt); echo obj.sDate;//返回值:2025-09-12 echo obj._datetoStr(20250912);//返回值:2025-09-12 echo obj.formatS(".");//返回值:2025.09.12 return 1; ``` 打印结果如下: ### TSL 内置对象使用大全 #### 内容 - TSL 内置对象使用大全简介 - FTP 对象 - TRSA - TCipher - TStringList 对象 - THashedStringList 对象 - TStream 对象 - TMemoryStream 对象 - THandleStream 对象 - TFileStream 对象 - TIniFile 对象 - TMemIniFile 对象 - TRegistryIniFile 对象 - TWebResponse 对象 - TWebRequest 对象 - TCookieCollection 对象 - TCookie 对象 - TSessionMan 对象 - TSession 对象 - SMTP 对象 - Pop3 对象 - MailMsg 对象 - MessagePart 对象 #### TSL 内置对象使用大全简介 TSL 支持三种对象:COM 对象,TSL 内置对象,TSL 语言编写的对象。 TSL 内置对象是二进制开发的 TSL 对象,独立的 TSL 内置对象可以在 TSL 语言里继承,但是不能重载二进制的内置对象的方法。 #### FTP 对象 说明:FTP 对象通过文件传输协议(FTP)提供对文件服务器的客户端访问。FTP 对象的方法和属性作用于打开、登陆已经关闭 FTP 连接,同事用于上传、下载、重命名、删除和获得 FTP 服务器上的文件信息。 ##### 内容 - FTP 对象的创建 - FTP 对象的方法 - FTP 对象属性 ##### FTP 对象的创建 范例 范例 1:创建对象未指定配置名,手动设置 FTP 配置并连接登录服务器 ```text obj := CreateObject("FTP"); obj.host := "ftp.tinysoft.com.cn"; obj.port := 20; obj.username := username; obj.password := password; obj.connect();//连接服务器 obj.login();//登录服务器 return obj.RetrieveCurrentDir(); //连接并登录成功,返回当前所处目录(默认为"/") ``` 范例 2:创建对象时指定配置名,自动读取配置文件中的设置并连接登录服务器 配置文件为 Analyse.NET\PLUGIN\FileMgr.INI,配置格式如下: [CLASS:FTP] permit=local [FTP Settings] TSDN.Case.FTP:Port=20 TSDN.Case.FTP:UserName=username TSDN.Case.FTP:Password=password TSDN.Case.FTP=ftp.tinysoft.com.cn ```text obj := CreateObject("FTP","TSDN.Case.FTP"); return obj.RetrieveCurrentDir(); //连接并登录成功,返回当前所处目录(默认为"/") ``` ##### FTP 对象的方法 ###### 内容 - Abort - ChangeDir - ChangeDirUp - Connect - Delete - DisconnectNotifyPeer - FileDate - Get - Help - IsServerMDTZAndListTForm - List - Login - MakeDir - Noop - Put - Quit - Quote - ReInitialize - RemoveDir - Rename - ResumeSupported - RetrieveCurrentDir - SetCmdOpt - SetLang - SetModTime - SetModTimeGMT - Site - Size - Status - CRC ###### Abort 范例 ```text obj := CreateObject("FTP"); obj.host := "ftp.tinysoft.com.cn"; obj.port := 20; obj.username := username; obj.password := password; obj.connect();//连接服务器 obj.login();//登录服务器 return obj.Abort(); //终止连接成功,返回0 ``` ###### ChangeDir 范例 ```text obj := CreateObject("FTP"); obj.host := "ftp.tinysoft.com.cn"; obj.port := 20; obj.username := username; obj.password := password; obj.connect();//连接 obj.login();//登录 obj.changedir('/test');//将FTP服务器上的当前目录更改为"/test" return obj.RetrieveCurrentDir(); //修改成功,当前目录应为"/test" ``` ###### ChangeDirUp 范例 ```text obj := CreateObject("FTP"); obj.host := "ftp.tinysoft.com.cn"; obj.port := 20; obj.username := username; obj.password := password; obj.connect();//连接 obj.login();//登录 obj.changedir('/test');//将FTP服务器上的当前目录更改为"/test" obj.changeDirUp();//跳转到当前目录的上一级目录"/" return obj.RetrieveCurrentDir(); //跳转成功,当前目录应为"/" ``` ###### Connect 范例 ```text obj := CreateObject("FTP"); obj.host := "ftp.tinysoft.com.cn"; obj.port := 20; obj.username := username; obj.password := password; return obj.connect(); //连接成功,返回0 ``` ###### Delete 范例 删除 FTP 服务器指定文件 ```text obj := CreateObject("FTP"); obj.host := "ftp.tinysoft.com.cn"; obj.port := 20; obj.username := username; obj.password := password; //连接FTP服务器 obj.connect(); //登录 obj.Login(); //删除Test.txt文件 obj.delete("Test.txt"); //验证文件是否被删除 return obj.FileDate("Test.txt",0); //获取文件时间,若无该文件,返回0 ``` ###### DisconnectNotifyPeer ###### FileDate 范例 获取 FTP 服务器指定文件的最后修改时间 ```text obj := CreateObject("FTP"); obj.host := "ftp.tinysoft.com.cn"; obj.port := 20; obj.username := username; obj.password := password; //连接FTP服务器 obj.connect(); //登录 obj.Login(); ret:= obj.FileDate("Test.txt",0); return DateTimeToStr(ret); //"2024-07-31 14:28:00" ``` ###### Get 范例 从服务器下载指定文件至本机 ```text obj := CreateObject("FTP"); obj.host := "ftp.tinysoft.com.cn"; obj.port := 20; obj.username := username; obj.password := password; //连接FTP服务器 obj.connect(); //登录 obj.Login(); obj.TryNATFastTrack := 1; //下载文件 st := new TFileStream("","D:\\test\\1.txt",65535); obj.get("FtpTest.txt",st,0); //若下载成功,可在本机对应位置查看文件 ``` ###### Help ###### IsServerMDTZAndListTForm ###### List 范例 查看当前服务器目录下匹配到的文件列表 ```text obj := CreateObject("FTP"); obj.host := "ftp.tinysoft.com.cn"; obj.port := 20; obj.username := username; obj.password := password; //连接FTP服务器 obj.connect(); //登录 obj.Login(); AFiles := new TStringList(); //获取当前目录所有.txt文件信息 obj.List(AFiles,'*.txt',true); return AFiles.GetText(); //字符串: "-rw-r--r-- 1 1001 1001 17 Apr 09 16:07 test01.txt -rw-r--r-- 1 1001 1001 0 Sep 16 2023 test02.txt -rw-r--r-- 1 1001 1001 38 Jul 25 17:26 test03.txt" ``` ###### Login 范例 ```text obj := CreateObject("FTP"); obj.host := "ftp.tinysoft.com.cn"; obj.port := 20; obj.username := username; obj.password := password; //连接FTP服务器 obj.connect(); //登录 obj.Login(); return obj.RetrieveCurrentDir(); //获取当前所在目录,若登录成功,则返回"/" ``` ###### MakeDir 范例 在服务器当前目录中创建新文件夹 ```text obj := CreateObject("FTP"); obj.host := "ftp.tinysoft.com.cn"; obj.port := 20; obj.username := username; obj.password := password; //连接FTP服务器 obj.connect(); //登录 obj.Login(); obj.MakeDir("newDir"); //若创建成功,可在服务器中查看或使用FAQ: List 查看 ``` ###### Noop ###### Put 范例 将本机指定文件上传至服务器 ```text obj := CreateObject("FTP"); obj.host := "ftp.tinysoft.com.cn"; obj.port := 20; obj.username := username; obj.password := password; //连接FTP服务器 obj.connect(); //登录 obj.Login(); //构造TStream对象 filepath := "D:\\test\\Test.txt"; st := new TMemoryStream(); st.LoadFromFile("",filepath); obj.Put(st,"put.txt",false); //若上传成功,可在服务器中查看或使用FAQ: Get 下载后在本机查看 ``` ###### Quit ###### Quote ###### ReInitialize ###### RemoveDir 范例 从服务器删除指定文件夹 ```text obj := CreateObject("FTP"); obj.host := "ftp.tinysoft.com.cn"; obj.port := 20; obj.username := username; obj.password := password; //连接FTP服务器 obj.connect(); //登录 obj.Login(); obj.Remove("testDir"); //若删除成功,可在服务器中查看或使用FAQ: List 查看 ``` ###### Rename 范例 范例一:重命名文件夹 ```text obj := CreateObject("FTP"); obj.host := "ftp.tinysoft.com.cn"; obj.port := 20; obj.username := username; obj.password := password; //连接FTP服务器 obj.connect(); //登录 obj.Login(); obj.rename("testDir","newDir"); //若重命名成功,可在服务器中查看或使用FAQ: List 查看 ``` 范例二:重命名文件 ```text obj := CreateObject("FTP"); obj.host := "ftp.tinysoft.com.cn"; obj.port := 20; obj.username := username; obj.password := password; //连接FTP服务器 obj.connect(); //登录 obj.Login(); obj.rename("test.txt","new.txt"); //若重命名成功,可在服务器中查看或使用FAQ: List 查看 ``` ###### ResumeSupported ###### RetrieveCurrentDir 范例 获取当前所在目录 ```text obj := CreateObject("FTP"); obj.host := "ftp.tinysoft.com.cn"; obj.port := 20; obj.username := username; obj.password := password; //连接FTP服务器 obj.connect(); //登录 obj.Login(); return obj.RetrieveCurrentDir(); //字符串:"/" ``` ###### SetCmdOpt ###### SetLang ###### SetModTime ###### SetModTimeGMT ###### Site ###### Size 范例 查看服务器当前目录指定文件大小 ```text obj := CreateObject("FTP"); obj.host := "ftp.tinysoft.com.cn"; obj.port := 20; obj.username := username; obj.password := password; //连接FTP服务器 obj.connect(); //登录 obj.Login(); return obj.Size("test.txt"); //整数,18 ``` ###### Status ###### CRC ##### FTP 对象属性 ###### 内容 - Account - AUTHCmd - AutoLogin - AutoIssueFEAT - CanResume - CurrentTransferMode - DataPort - DataPortMin - DataPortMax - DirFormat - ExternalIP - Host - LangsSupported - LastCmdResult - ListResult - Passive - Password - Port - ProxyHost - ProxyPort - ProxyUsername - ProxyPassword - ProxyType - ReadTimeout - SupportsVerification - SystemDesc - TransferTimeout - TransferType - TryNATFastTrack - UseCCC - UseExtensionDataPort - UseMLIS - Username - UseTLS - UsingExtDataPort - UsingNATFastTrack - UsingSFTP - PassiveUseControlHost - ListenTimeout - TransferMode ###### Account ###### AUTHCmd ###### AutoLogin ###### AutoIssueFEAT ###### CanResume ###### CurrentTransferMode ###### DataPort ###### DataPortMin ###### DataPortMax ###### DirFormat ###### ExternalIP ###### Host ###### LangsSupported ###### LastCmdResult ###### ListResult ###### Passive ###### Password ###### Port ###### ProxyHost ###### ProxyPort ###### ProxyUsername ###### ProxyPassword ###### ProxyType ###### ReadTimeout ###### SupportsVerification ###### SystemDesc ###### TransferTimeout ###### TransferType ###### TryNATFastTrack ###### UseCCC ###### UseExtensionDataPort ###### UseMLIS ###### Username ###### UseTLS ###### UsingExtDataPort ###### UsingNATFastTrack ###### UsingSFTP ###### PassiveUseControlHost ###### ListenTimeout ###### TransferMode - Account - AUTHCmd - AutoLogin - AutoIssueFEAT - CanResume - CurrentTransferMode - DataPort - DataPortMin - DataPortMax - DirFormat - ExternalIP - Host - LangsSupported - LastCmdResult - ListResult - Passive - Password - Port - ProxyHost - ProxyPort - ProxyUsername - ProxyPassword - ProxyType - ReadTimeout - SupportsVerification - SystemDesc - TransferTimeout - TransferType - TryNATFastTrack - UseCCC - UseExtensionDataPort - UseMLIS - Username - UseTLS - UsingExtDataPort - UsingNATFastTrack - UsingSFTP - PassiveUseControlHost - ListenTimeout - TransferMode #### TRSA TRsa 类用于提供 RSA 算法。RSA 是非对称加密算法,加解密速度慢,被加密明文的长度有限制,通常用于密钥传输、证书签名等场景。TRsa 类提供的成员方法主要包括:密钥生成、密钥读写、加解密。 ##### 内容 - TRSA 的属性 - TRSA 的方法 - TRSA 使用说明以及范例 ##### TRSA 的属性 ###### 内容 - PublicKey - PrivateKey ###### PublicKey ###### PrivateKey ##### TRSA 的方法 ###### 内容 - GenerateKey - PubEncrypt - PriEncrypt - PubDecrypt - PriDecrypt ###### GenerateKey ###### PubEncrypt ###### PriEncrypt ###### PubDecrypt ###### PriDecrypt ##### TRSA 使用说明以及范例 在使用加密和解密方法前必须确保 TRsa 对象中已经正确地设置了密钥。 GenerateKey 方法会生成一对新的密钥,而给 PublicKey 和 PrivateKey 赋值可以分别载入一个已经存在的公钥和私钥,要注意的是给 PublicKey 和 PrivateKey 中的任何一个赋值,系统都会先将公钥和私钥同时重置,然后再分别设置公钥和私钥。 公钥和私钥都以 PKCS#1 格式编码。 被加密的数据长度通常不能超过密钥字节数-11,否则函数将执行失败。例如使用 1024 位密钥,即 128 字节,那么被加密数据不能超过 117 个字节。加密后的密文数据长度和密钥字节数相同。 示例: 下述代码展示了两种加密解密过程: 1.文本内容->公钥加密->私钥对加密内容解密 2.文本内容->私钥加密->公钥对加密内容解密
filename := 'd:\\a.txt';
size := filesize("",filename);
ReadFile(rwraw(),"",filename,0,size,file_str);//读取文本内容
rsa_obj := CreateObject('TRsa');
rsa_obj.GenerateKey(1024);
rsa_pubkey := rsa_obj.PublicKey;//公钥
rsa_prikey := rsa_obj.PrivateKey;//私钥
rsa_obj_1 := CreateObject('TRsa');
rsa_obj_1.PublicKey := rsa_pubkey;
rsa_pub_enc := rsa_obj_1.PubEncrypt(file_str);//使用公钥加密文本内容
rsa_obj_1.PrivateKey := rsa_prikey;
rsa_pri_dec := rsa_obj_1.PriDecrypt(rsa_pub_enc);//使用私钥解密
rsa_pri_enc := rsa_obj_1.PriEncrypt(file_str);//使用私钥加密文本内容
rsa_obj_1.PublicKey := rsa_pubkey;
rsa_pub_dec := rsa_obj_1.PubDecrypt(rsa_pri_enc);//使用公钥解密
return array(
'文本内容':file_str,
'RSA私钥':rsa_prikey,
'RSA公钥':rsa_pubkey,
'RSA公钥加密':EncodeRadixStr(rsa_pub_enc,'',16),
'RSA私钥解密':rsa_pri_dec,
'RSA私钥加密':EncodeRadixStr(rsa_pri_enc,'',16),
'RSA公钥解密':rsa_pub_dec
);
#### TCipher TCipher 类用于多重对称加密算法,其支持的算法有:
mode 算法名 密钥长度(字节) IV长度(字节)
1 DES_ECB 8 0
2 DEC_CBC 8 8
3 DES_CFB 8 8
4 DES_OFB 8 8
5 IDEA_ECB 16 0
6 IDEA_CBC 16 8
7 IDEA_CFB 16 8
8 IDEA_OFB 16 8
9 AES_128_ECB 16 0
10 AES_128_CBC 16 16
11 AES_128_CFB 16 16
12 AES_128_OFB 16 16
13 AES_192_ECB 24 0
14 AES_192_CBC 24 16
15 AES_192_CFB 24 16
16 AES_192_OFB 24 16
17AES_256_ECB320
18AES_256_CBC3216
19AES_256_CFB3216
20AES_256_OFB3216
##### 内容 - TCipher 类的属性 - TCipher 类的方法 - TCipher 使用说明以及范例 ##### TCipher 类的属性 ###### 内容 - Mode - Password - Key - IV - KeyLength - LVLength ###### Mode ###### Password ###### Key ###### IV ###### KeyLength ###### LVLength ##### TCipher 类的方法 ###### 内容 - Encrypt - EncryptFile - Decrypt - DecryptFile ###### Encrypt ###### EncryptFile 范例: ```text cipher_obj:=CreateObject('TCipher',7); //使用DES_CBC算法 cipher_obj.Password:='Tinysoft'; //设定密码 //给指定文件进行加密,并将加密后的内容写入指定文件中 cipher_obj.EncryptFile('', 'd:\\test\\test.txt', '', 'd:\\test\\test2.txt'); //给指定文件进行解密,并将解密后的内容写入指定文件中 cipher_obj.DecryptFile('', 'd:\\test\\test2.txt', '', 'd:\\test\\test3.txt'); return 1; ``` ###### Decrypt ###### DecryptFile ##### TCipher 使用说明以及范例 TCipher 类所支持的加密算法是基于数据块的对称加密算法。在使用类进行处理前,首先应设置 Mode 属性,指定算法种类。 对称加密算法加密和解密使用相同的密钥(key)和初始化向量(IV)。初始化向量的作用在于:TCipher 提供的多数加密算法为了提高加密强度,在密文的块与块之间实现了一定的关联,初始化向量为第一块设定初始关联,如果初始化向量不正确,数据会出现错误。不同算法的密钥和初始化向量的长度是不同的,TCipher 提供了 KeyLength 和 IVLength 可以取得密钥和初始化向量的长度。在加密和解密前可以通过 Key 和 IV 属性设置密钥和初始化向量,因为 key 和 IV 都是二进制的,因此应使用 hex 字符串进行设置: ```text cipher_obj:=CreateObject('TCipher', 2); //使用DES_CBC算法 //测试使用key和IV进行加密 key8:='0102030405060708'; iv8:='FFFFFFFFFFFFFFFF'; cipher_obj.key:=key8; cipher_obj.iv:=iv8; ``` 因为 key 和 IV 是二进制的,而且在有的算法中较长,在某些应用场景中不便于读取和记忆。TCipher 还提供了 Password 属性。通过 Password 属性可以方便地设置 key 和 IV,TCipher 类会根据设置的 Password 字符串,通过哈希算法计算出一个 key 和 IV,这样加解密的双方就可以用一个 Password 实现加密和解密了。示例: ```text filename:='d:\\a.txt; size:=filesize("",filename); //获取文件大小 ReadFile(rwraw(),"",filename,0,size,file_str); //对称加密算法类 cipher_obj:=CreateObject('TCipher', 2); //使用DES_CBC算法 cipher_obj.Password:='Tinysoft'; //设定密码 des_cbc_str:=cipher_obj.Encrypt(file_str);//加密字符串 orig_des_cbc:=cipher_obj.Decrypt(des_cbc_str);//解密字符串 ``` 文件加解密过程中 src_alias 和 dest_alias 参数用于指定文件的目录别名。下面是文件加解密示例(本地执行): ```text cipher_obj:=CreateObject('TCipher', 2); //使用DES_CBC算法 cipher_obj.Password:='Tinysoft'; //设定密码 //加密文件 cipher_obj.EncryptFile('', 'd:\\test.bmp', '', 'd:\\test.bmp.enc'); //解密文件 cipher_obj.DecryptFile('', 'd:\\test.bmp.enc', '', 'd:\\test_dec.bmp'); ``` #### TStringList 对象 ##### 内容 - TStringList 对象的创建 - TStringList 对象的属性 - TStringList 的方法 - TStringList 对象重载[]算符 ##### TStringList 对象的创建 调用:CreateObject('TStringList') ##### TStringList 对象的属性 ###### 内容 - Values - StringsW - CommaTextW - ValueFromIndex - TextW - GetText - GetTextW - Capacity - CaseSensitive - Count - Duplicates - Sorted - Strings - CommaText - DelimitedText - Delimiter - Names - NameValueSeparator - QuoteChar - Text ###### Values 范例 ```text obj:=CreateObject('TStringList'); obj.Delimiter:=";"; obj.DelimitedText:='A=ABC;B=123;C=456.;D=abc'; SN:=obj.count; r:=array(); for i:=0 to SN-1 do begin r[i,'name']:=obj.Names(i);//获取name值 r[i,'value']:=obj.values(obj.Names(i));//获取指定name对应的value值 end return r; ``` //返回: ###### StringsW - Values - StringsW - CommaTextW - ValueFromIndex - TextW - GetText - GetTextW - Capacity - CaseSensitive - Count - Duplicates - Sorted - Strings - CommaText - DelimitedText - Delimiter - Names - NameValueSeparator - QuoteChar - Text ###### CommaTextW - Values - StringsW - CommaTextW - ValueFromIndex - TextW - GetText - GetTextW - Capacity - CaseSensitive - Count - Duplicates - Sorted - Strings - CommaText - DelimitedText - Delimiter - Names - NameValueSeparator - QuoteChar - Text ###### ValueFromIndex 范例 ```text obj:=CreateObject('TStringList'); obj.Delimiter:=";"; obj.DelimitedText:='A=ABC;B=123;C=456.;D=abc'; s0:=obj.ValueFromIndex(1);//读取第1个 obj.ValueFromIndex(1):="888"; //写入,即给指定位置的value重新赋值 return array(s0,obj.DelimitedText); ``` //返回结果如下: ###### TextW - Values - StringsW - CommaTextW - ValueFromIndex - TextW - GetText - GetTextW - Capacity - CaseSensitive - Count - Duplicates - Sorted - Strings - CommaText - DelimitedText - Delimiter - Names - NameValueSeparator - QuoteChar - Text ###### GetText - Values - StringsW - CommaTextW - ValueFromIndex - TextW - GetText - GetTextW - Capacity - CaseSensitive - Count - Duplicates - Sorted - Strings - CommaText - DelimitedText - Delimiter - Names - NameValueSeparator - QuoteChar - Text ###### GetTextW - Values - StringsW - CommaTextW - ValueFromIndex - TextW - GetText - GetTextW - Capacity - CaseSensitive - Count - Duplicates - Sorted - Strings - CommaText - DelimitedText - Delimiter - Names - NameValueSeparator - QuoteChar - Text ###### Capacity ###### CaseSensitive ###### Count ###### Duplicates 范例 ```text obj:=CreateObject('TStringList'); obj.Delimiter:=","; obj.Sorted:=1;//自动排序 obj.Duplicates:=2; //重复串出错 obj.DelimitedText:='A=abc,B=123,C=abc,F=996,E=abd'; obj.Add("b=123");//插入一个重复串 return obj.DelimitedText; ``` 执行报错: ###### Sorted 范例: ```text obj:=CreateObject('TStringList'); obj.CommaText:='C=456.,a=abc,E=666,B=123'; echo obj.CommaText,"\r\n"; obj.Sorted:=1;//设定排序后 echo obj.CommaText,"\r\n"; return ; ``` 打印结果: C=456.,a=abc,E=666,B=123 a=abc,B=123,C=456.,E=666 差异说明 排序与系统有关,Linux 中,默认是以 C 为标准,按 ASCII 大小排序或比较大小的(即区分大小写),而 windows 中,按字母顺序进行(即不区分大小写)。 例如运行下列代码: ```text obj:=CreateObject('TStringList'); obj.CommaText:='C=456.,c=A123,a=abc,A=ABC,E=666,B=123'; echo obj.CommaText,"\r\n"; obj.Sorted:=1;//设定排序后 echo obj.CommaText,"\r\n"; return ; ``` 在 Windows 中打印的结果为(排序按字母顺序): C=456.,c=A123,a=abc,A=ABC,E=666,B=123 a=abc,A=ABC,B=123,C=456.,c=A123,E=666 在 Linux 中打印的结果为(按 ASCII 码): C=456.,c=A123,a=abc,A=ABC,E=666,B=123 A=ABC,B=123,C=456.,E=666,a=abc,c=A123 排序后的顺序是存在差异的。但在同一系统中,每次表现是一定的。 ###### Strings 范例 ```text obj:=CreateObject('TStringList'); obj.Delimiter:=";"; obj.DelimitedText:='A=ABC;B=123;C=456.;D=abc'; return obj.strings(1); //读 ``` //结果:B=123 ```text obj:=CreateObject('TStringList'); obj.Delimiter:=";"; obj.DelimitedText:='A=ABC;B=123;C=456.;D=abc'; obj.strings(1):="EF=aaa";//写 return obj.DelimitedText; ``` //结果:A=ABC;EF=aaa;C=456.;D=abc ###### CommaText 范例 ```text obj:=CreateObject('TStringList'); obj.CommaText:='ABC,12,"3,a""bc"'; return array(obj.strings(0),obj.strings(1),obj.strings(2)); ``` //返回: ###### DelimitedText 范例 可参考 QuoteChar ###### Delimiter 范例 ```text obj:=CreateObject('TStringList'); obj.Delimiter:=";"; //这一句必须设置在obj.DelimitedText赋值之前 obj.DelimitedText:='ABC,;123,;456.;abc'; SN:=obj.count; r:=array(); for i:=0 to SN-1 do r[i]:=obj.strings(i); return r; ``` //返回: ###### Names 范例 可参考 values ###### NameValueSeparator ###### QuoteChar 范例 ```text obj:=CreateObject('TStringList'); obj.QuoteChar:="&"; obj.Delimiter:=";"; obj.DelimitedText:='&AB;C,&;123,;456.;abc'; SN:=obj.count; r:=array(); for i:=0 to SN-1 do r[i]:=obj.strings(i); return r; ``` 返回结果如下:第一个串中,存在分割符;,需要用指定的引用符&将当前完整的串引用起来。 ###### Text 范例 ```text obj:=CreateObject('TStringList'); obj.NameValueSeparator:=" ";//空格为间隔符 obj.Text:='A a B b C c D d '; SN:=obj.count; r:=array(); for i:=0 to SN-1 do begin r[i,'n']:=obj.Names(i); r[i,'v']:=obj.values(obj.Names(i)); end return r; ``` 返回结果: ##### TStringList 的方法 ###### 内容 - ExChange - Add - Clear - Delete - Find - IndexOf - Insert - Sort - AddStrings - Append - Assign - Equals - GetText - IndexOfName - LoadFromFile - LoadFromStream - Move - SaveToFile - SaveToStream - SetText ###### ExChange 范例 将位置 0 与位置 2 的内容进行互换 ```text obj:=CreateObject('TStringList'); obj.CommaText:='A=ABC,B=123,C=abc'; obj.ExChange(0,2); return obj.CommaText; ``` //返回结果:C=abc,B=123,A=ABC ###### Add 范例 ```text obj:=CreateObject('TStringList'); obj.CommaText:='A=ABC,B=123,C=abc'; index:=obj.Add("X=DDD"); echo index; sN:=obj.count; r:=array(); for i:=0 to SN-1 do begin r[i,'n']:=obj.Names(i); r[i,'v']:=obj.values(obj.Names(i)); end return r; ``` 其中,index 值为 3,添加后结果为: ###### Clear ###### Delete ###### Find 范例 ```text obj:=CreateObject('TStringList'); obj.Sorted:=1; obj.CommaText:='C=456.,D=abc,A=ABC,E=666,F=A123,B=123'; f:=obj.Find("E=666",Index); if f then return Index; else return '查找失败'; ``` //返回 4 ###### IndexOf ###### Insert ###### Sort 差异说明 排序结果与系统的默认排序规则有关,具体可参考: FAQ:Sorted 范例 ```text obj:=CreateObject('TStringList'); obj.CommaText:='C=456.,a=abc,E=666,B=123'; echo obj.CommaText,"\r\n"; obj.sort();//设定排序后 echo obj.CommaText,"\r\n"; return ; ``` 打印结果: C=456.,a=abc,E=666,B=123 a=abc,B=123,C=456.,E=666 ###### AddStrings 范例 ```text bj:=CreateObject('TStringList'); obj.CommaText:='A=ABC,B=123,C=abc'; obj2:=CreateObject('TStringList'); obj2.CommaText:='A=DDD,G=666'; obj.AddStrings(obj2); return obj.CommaText; ``` 返回结果:"A=ABC,B=123,C=abc,A=DDD,G=666" ###### Append ###### Assign 范例 ```text obj:=CreateObject('TStringList'); obj.Delimiter:=";"; obj.DelimitedText:='A=DDD;G=666'; obj2:=CreateObject('TStringList'); obj2.Delimiter:=","; obj2.Assign(obj);//复制 return array(obj2.Delimiter,obj2.DelimitedText); ``` 返回结果:array(";","A=DDD;G=666") ###### Equals ###### GetText ###### IndexOfName ###### LoadFromFile 范例 //远端用户需要本地执行这个操作 ```text LJ:="E:\\Test\\Case-save.txt"; obj:=CreateObject('TStringList'); obj.LoadFromFile('',LJ); return obj.CommaText; ``` 返回: A a,B b,C c,D d ###### LoadFromStream 范例 ```text ws := new TMemoryStream(); ws.write("A=aaa",5); ws.position:=0; obj:=CreateObject('TStringList'); obj.LoadFromStream(ws); return obj.CommaText; ``` 返回结果:A=aaa ###### Move ###### SaveToFile 范例 //远端用户需要本地执行这个操作 ```text pathname:= "E:\\Test\\Case-save.txt"; obj:=CreateObject('TStringList'); obj.Text:=TestStr1(); obj.SaveToFile('',pathName); ``` 执行后本地生成 txt 文档: ###### SaveToStream 范例 ```text ws := new TMemoryStream(); obj:=CreateObject('TStringList'); obj.Text:= 'A a B b C c D d '; obj.SaveToStream(ws); return ws.size; //返回20 ``` ###### SetText ##### TStringList 对象重载[]算符 可通过 TStringList 对象直接[]下标方式访问字符串内容 例如: ```text ts:=new TStringList(); ts.CommaText:="aaa,bbb,222,111"; echo ts[1]; //数字下标 ts.CommaText:="A=aaa,B=bbb,C=222,D=111"; echo ts["B"]; //字符串下标 ``` 打印结果: bbb bbb #### THashedStringList 对象 THashedStringList 对象的使用与 TStringList 完全相同,不同的地方是 THashedStringList 进行了 Hash,所以在检索字符串的时候的效率会比 TStringList 快很多,但是由于要建立 Hash,所以内存占用与插入效率会低于 TStringList。 参见:TStringList 对象 ##### 内容 - THashedStringList 对象的创建 ##### THashedStringList 对象的创建 调用:CreateObject('THashedStringList') 参见:TStringList 对象 #### TStream 对象 TStream 类型是 TMemoryStream,THandleStream,TFileStream 对象的父类,本身是一个纯虚对象,不可被直接创建。 ##### 内容 - TStream 的属性 - TStream 的方法 ##### TStream 的属性 ###### 内容 - Position - Size ###### Position 指针初始位置从 0 开始,当写入内容后指针会更新,自动指向尾部。 如: ```text obj:=CreateObject("TMemoryStream"); echo obj.Position; buffer:="ABC 123"; p1:= obj.write(buffer,10); echo obj.Position; p2:= obj.write(buffer,10); echo obj.Position; ``` 打印结果为: 0 10 20 ###### Size ##### TStream 的方法 ###### 内容 - CopyFrom - Read - Seek - SetSize - Write ###### CopyFrom 范例:复制一个 TStream 流中的局部内容 ```text obj:=CreateObject("TMemoryStream"); buffer:="ABC-123"; obj.write(buffer,8); obj.position:=2;//重新指定当前位置 obj2:=CreateObject("TMemoryStream"); cf:=obj2.CopyFrom(obj,4);//从源流中的位置2起开始复制4个字节的内容 buffer:="xxxxxxxxxxxx"; //12个字节 obj2.position:=0; obj2.read(buffer,7);//将obj2流的内容读到buffer中 return buffer; ``` 返回结果为:C-12xxxxxxxx ###### Read 范例:读流中的内容,注意需要先通过 position 设置起始位置 ```text obj:=CreateObject("TMemoryStream"); echo "起始位置:",obj.position; buffer:="ABC-123"; //7个字节 obj.Write(buffer,6);//写入6个字节 echo "写入后的位置:",obj.position; obj.position:=0;//当前位置重新设置为起始位置 buffer:="xxxxxxxxxxxx"; //12个字节 obj.read(buffer,7); //将流中的7个字节的内容读到buffer中 echo "读取后的位置:",obj.position; return buffer; ``` 执行后打印信息: 起始位置:0 写入后的位置:6 读取后的位置:6 返回的结果为:ABC-12xxxxxx ###### Seek 范例 01:从尾部进行移动 ```text obj:=CreateObject("TMemoryStream"); buffer:="ABC 123"; obj.write(buffer,8); echo "移动前位置:",obj.position; p:= obj.seek(4,2);//从尾部进行移动4个字节 echo "移动后位置:",obj.position," 返回的位置:",p; return p; ``` 打印的结果如下: 移动前位置:8 移动后位置:12 返回的位置:12 ###### SetSize ###### Write #### TMemoryStream 对象 参见:TStream 对象 ##### 内容 - TMemoryStream 对象的创建 - TMemoryStream 的方法 ##### TMemoryStream 对象的创建 调用:CreateObject('TMemoryStream') ##### TMemoryStream 的方法 ###### 内容 - Clear - LoadFromFile - LoadFromStream - SaveToFile - SaveToStream ###### Clear ###### LoadFromFile 范例:加载本地的 txt 的内容,注:该功能是与本地交互,因此,需要在本地执行 ```text LJ:="E:\\test\\TestAAA.txt"; obj:=CreateObject("TMemoryStream"); obj.position:=0; //设置当前起始位置 obj.LoadFromFile("",LJ);//装载指定文件内容 buffer:=""; SetLength(buffer,10); obj.position:=0; obj.read(buffer,10); //读取前10个节字的内容到buffer中 return buffer; ``` 返回:Tinysoft h 其中,文件 TestAAA.txt 的内容为: ###### LoadFromStream 范例: ```text obj:=CreateObject("TMemoryStream"); buffer:="ABC-123"; obj.write(buffer,8); obj2:=CreateObject("TMemoryStream"); cf:= obj2.LoadFromStream(obj);//将obj加载到obj2中 buffer:=""; SetLength(buffer,8); obj2.position:=0; obj2.read(buffer,8); return buffer; ``` 返回:"ABC-123\0" ###### SaveToFile 范例:将流中的内容存贮到指定的 txt 文件中 ```text LJ:="E:\\test\\TestBBB.txt"; obj:=CreateObject("TMemoryStream"); obj.position:=0; //设置当前起始位置 buffer:="ABC-123"; obj.write(buffer,8); obj.savetoFile("",LJ);//保存 ``` 运行后,本地的 TestBBB.txt 文件如下: ###### SaveToStream 范例:将实例 obj2 的内容保存到实例 obj 中去 ```text obj:=CreateObject("TMemoryStream"); buffer1:="xxxxxxxx"; obj.write(buffer1,8); obj2:=CreateObject("TMemoryStream"); buffer:="ABC-123"; obj2.write(buffer,7); //obj.position:=0;//改变保存的起始位置 cf:= obj2.SaveToStream(obj);//将obj2保存到obj中 buffer:=""; SetLength(buffer,15); obj.position:=0; obj.read(buffer,15); return buffer; ``` 返回:"xxxxxxxxABC-123" #### THandleStream 对象 参见:TStream 对象 ##### 内容 - THandleStream 对象的创建 ##### THandleStream 对象的创建 - THandleStream 对象的创建 #### TFileStream 对象 参见:TStream 对象 ##### 内容 - TFileStream 对象的创建 ##### TFileStream 对象的创建 范例: ```text FileName:="E:\\Test\\TFileCase01.txt"; //-新建一个txt文件并打开 obj:= CreateObject("TFileStream","",FileName,65535); buffer:="ABC 123"; p:= obj.write(buffer,7); //写入 //-读取 b:=""; SetLength(b,7); obj.Position:=0; //必须设置起始位置,否则失败 obj.Read(b,7); return b; ``` 返回字符串:ABC 123 #### TIniFile 对象 ##### 内容 - TIniFile 的创建 - TIniFile 的方法 ##### TIniFile 的创建 调用:CreateObject('TIniFile',Alias,FileName:string) 参数: Alias:字符串类型,目录别名。 FileName:字符串类型,INI 文件名。 ##### TIniFile 的方法 ###### 内容 - SectionExists - ReadString - WriteString - ReadInteger - WriteInteger - ReadBoolean - WriteBoolean - ReadBinaryStream - WriteBinaryStream - ReadDate - WriteDate - ReadDateTime - WriteDateTime - ReadFloat - WriteFloat - ReadSection - ReadSectionValues - ReadSections - EraseSection - DeleteKey - ValueExists ###### SectionExists ###### ReadString ###### WriteString ###### ReadInteger ###### WriteInteger ###### ReadBoolean ###### WriteBoolean ###### ReadBinaryStream ###### WriteBinaryStream ###### ReadDate ###### WriteDate ###### ReadDateTime ###### WriteDateTime ###### ReadFloat ###### WriteFloat ###### ReadSection ###### ReadSectionValues ###### ReadSections ###### EraseSection ###### DeleteKey ###### ValueExists #### TMemIniFile 对象 参考:TIniFile 对象,TIniFile 的方法对 TmemIniFile 同样适用。 ##### 内容 - TMemIniFile 的创建 - TMemIniFile 的方法 - TMemIniFile 的属性 ##### TMemIniFile 的创建 范例 ```text //创建TMemIniFile对象 obj:= CreateObject("TMemIniFile"); //设置内容 sLobj:=new tstringlist(); sLobj.LoadFromFile("","D:\\Test\\File.ini"); obj.SetStrings(sLobj); //进行其他操作 ... ``` ##### TMemIniFile 的方法 ###### 内容 - Clear - GetStrings - SetStrings ###### Clear 范例 ini 文件内容如下: [Test] string=TinySoft [ReadStream] array=0a021f35 string=4265376941725678666a3871 ```text //创建TMemIniFile对象 obj:= CreateObject("TMemIniFile"); //设置内容 sLobj:=new tstringlist(); sLobj.LoadFromFile("","D:\\Test\\File.ini"); obj.SetStrings(sLobj); //清空设置的内容 obj.clear(); //获取设置好的内容 getObj:=new TStringList(); obj.GetStrings(getObj); return getObj.GetText(); ``` 结果:"" ###### GetStrings 范例 ini 文件内容如下: [Test] string=TinySoft [ReadStream] array=0a021f35 string=4265376941725678666a3871 ```text //创建TMemIniFile对象 obj:= CreateObject("TMemIniFile"); //设置内容 sLobj:=new tstringlist(); sLobj.LoadFromFile("","D:\\Test\\File.ini"); obj.SetStrings(sLobj); //获取设置好的内容 getObj:=new TStringList(); obj.GetStrings(getObj); return getObj.GetText(); ``` 结果: ###### SetStrings 范例 ini 文件内容如下: [Test] string=TinySoft [ReadStream] array=0a021f35 string=4265376941725678666a3871 ```text //创建TMemIniFile对象 obj:= CreateObject("TMemIniFile"); //设置内容 sLobj:=new tstringlist(); sLobj.LoadFromFile("","D:\\Test\\File.ini"); obj.SetStrings(sLobj); //获取设置好的内容 getObj:=new TStringList(); obj.GetStrings(getObj); return getObj.GetText(); ``` 结果: ##### TMemIniFile 的属性 ###### 内容 - CaseSensitive ###### CaseSensitive 范例 ini 文件内容如下: [Test] string=TinySoft [ReadStream] array=0a021f35 string=4265376941725678666a3871 ```text //创建TMemIniFile对象 obj := CreateObject("TMemIniFile"); //设置大小写相关 obj.CaseSensitive := 1; //设置内容 sLobj := new tstringlist(); sLobj.LoadFromFile("","D:\\Test\\File.ini"); obj.SetStrings(sLobj); //获取设置好的内容 t1 := obj.ReadString("Test","string",""); //大小写一致 t2 := obj.ReadString("test","string",""); //大小写不一致 return array(t1,t2); ``` 结果: #### TRegistryIniFile 对象 参考:TIniFile 对象 ##### 内容 - TRegistryIniFile 的创建 ##### TRegistryIniFile 的创建 - TRegistryIniFile 的创建 #### TWebResponse 对象 TWebResponse 是对 Delphi 的兼容对象,TSL 语言本身提供了函数化的输出以及头设置的方法,但是用 TWebResponse 可以方便熟悉 Delphi 开发的人员。 ##### 内容 - TWebResponse 的创建 - TWebResponse 的属性 - TWebResponse 的方法 ##### TWebResponse 的创建 调用:CreateObject('TWebResponse') ##### TWebResponse 的属性 ###### 内容 - Allow - ContentStream - ContentEncoding - ContentLength - ContentType - ContentVersion - Cookies - CustomHeaders - Date - DerivedFrom - Expires - HttpRequest - LastModified - Location - LogMessage - Realm - ReasonString - Server - StatusCode - Title - Version - WWWAuthenticate ###### Allow ###### ContentStream ###### ContentEncoding ###### ContentLength ###### ContentType ###### ContentVersion ###### Cookies 参考 TCookieCollection 对象 ###### CustomHeaders ###### Date ###### DerivedFrom ###### Expires ###### HttpRequest ###### LastModified ###### Location ###### LogMessage ###### Realm ###### ReasonString ###### Server ###### StatusCode ###### Title ###### Version - Allow - ContentStream - ContentEncoding - ContentLength - ContentType - ContentVersion - Cookies - CustomHeaders - Date - DerivedFrom - Expires - HttpRequest - LastModified - Location - LogMessage - Realm - ReasonString - Server - StatusCode - Title - Version - WWWAuthenticate ###### WWWAuthenticate ##### TWebResponse 的方法 ###### 内容 - GetCustomHeader - SendRedirect - SendResponse - SendStream - Sent - SetCookieField - SetCustomHeader ###### GetCustomHeader ###### SendRedirect ###### SendResponse ###### SendStream ###### Sent ###### SetCookieField ###### SetCustomHeader #### TWebRequest 对象 TWebRequest 是对 Delphi 的兼容对象,TSL 语言本身提供了函数化的获得请求信息的方法,但是用 TWebRequest 可以方便熟悉 Delphi 开发的人员。 ##### 内容 - TWebRequest 的创建 - TWebRequest 的属性 - TWebRequest 的方法 ##### TWebRequest 的创建 调用:CreateObject('TWebRequest') ##### TWebRequest 的属性 ###### 内容 - Accept - Authorization - CacheControl - Connection - Content - ContentEncoding - ContentFields - ContentLength - ContentType - ContentVersion - Cookie - CookieFields - Date - DerivedFrom - Expires - From - Host - IfModifiedSince - InternalPathInfo - InternalScriptName - Method - MethodType - PathInfo - PathTranslated - ProtocolVersion - Query - QueryFields - Referer - RemoteAddr - RemoteHost - ScriptName - ServerPort - Title - Url - UserAgent ###### Accept ###### Authorization ###### CacheControl ###### Connection ###### Content ###### ContentEncoding ###### ContentFields ###### ContentLength ###### ContentType ###### ContentVersion ###### Cookie ###### CookieFields ###### Date ###### DerivedFrom ###### Expires ###### From ###### Host ###### IfModifiedSince ###### InternalPathInfo ###### InternalScriptName ###### Method ###### MethodType ###### PathInfo - Accept - Authorization - CacheControl - Connection - Content - ContentEncoding - ContentFields - ContentLength - ContentType - ContentVersion - Cookie - CookieFields - Date - DerivedFrom - Expires - From - Host - IfModifiedSince - InternalPathInfo - InternalScriptName - Method - MethodType - PathInfo - PathTranslated - ProtocolVersion - Query - QueryFields - Referer - RemoteAddr - RemoteHost - ScriptName - ServerPort - Title - Url - UserAgent ###### PathTranslated ###### ProtocolVersion ###### Query ###### QueryFields ###### Referer ###### RemoteAddr ###### RemoteHost ###### ScriptName - Accept - Authorization - CacheControl - Connection - Content - ContentEncoding - ContentFields - ContentLength - ContentType - ContentVersion - Cookie - CookieFields - Date - DerivedFrom - Expires - From - Host - IfModifiedSince - InternalPathInfo - InternalScriptName - Method - MethodType - PathInfo - PathTranslated - ProtocolVersion - Query - QueryFields - Referer - RemoteAddr - RemoteHost - ScriptName - ServerPort - Title - Url - UserAgent ###### ServerPort ###### Title ###### Url ###### UserAgent ##### TWebRequest 的方法 ###### 内容 - ReadClient - WriteClient - ReadString - WriteString - WriteHeaders - ExtractContentFields - ExtractCookieFields - ExtractQueryFields - GetFieldByName - TranslateURI ###### ReadClient ###### WriteClient ###### ReadString ###### WriteString ###### WriteHeaders ###### ExtractContentFields ###### ExtractCookieFields ###### ExtractQueryFields ###### GetFieldByName ###### TranslateURI #### TCookieCollection 对象 TCookieCollection 不能直接创建,该对象从 TWebResponse 实例中通过 Cookies 属性获得。 参见:TWebResponse 对象,TCookie 对象 ##### 内容 - TCookieCollection 的方法 - TCookieCollection 的属性 ##### TCookieCollection 的方法 ###### 内容 - Add - Clear ###### Add 参考 TCookie 对象 ###### Clear ##### TCookieCollection 的属性 ###### 内容 - Count - Items - WebResponse ###### Count ###### Items 参考 TCookie 对象 ###### WebResponse 参考 TWebResponse 对象 #### TCookie 对象 ##### 内容 - TCookie 的属性 - TCookie 的方法 ##### TCookie 的属性 ###### 内容 - Domain - Expires - Name - Path - Secure - Value ###### Domain ###### Expires ###### Name ###### Path ###### Secure ###### Value ##### TCookie 的方法 ###### 内容 - HeaderValue - Assign - AssignTo ###### HeaderValue ###### Assign ###### AssignTo #### TSessionMan 对象 Session 管理器,可以用来在 WEB 服务器端存贮信息,例如存贮用户的登录状态。 参见:TSession 对象 ##### 内容 - TSessionMan 的创建 - TSessionMan 的方法 ##### TSessionMan 的创建 TSessionMan 对象的创建方法:CreateObject("TSessionMan"); ##### TSessionMan 的方法 ###### 内容 - NewSession - GetSession - DeleteSession - OnlineUser - OnlineSession ###### NewSession 参考 TSession 对象 ###### GetSession 参考 TSession 对象 ###### DeleteSession 参考 TSession 对象 ###### OnlineUser ###### OnlineSession #### TSession 对象 TSession 对象用于管理一个会话的数据存贮,由 TSessionMan 对象来创建,用来在 WEB 端存贮用户的信息。TSession 对象由 TMemIniFile 派生而来,所以 TMemIniFile 的方法和属性 TSession 也都支持。 参见:TSessionMan 对象,TMemIniFile 对象 ##### 内容 - TSession 的属性 ##### TSession 的属性 参见:TMemIniFile 对象 ###### 内容 - LastActive - Refs - LiveSeconds - UserId - SessionId ###### LastActive ###### Refs ###### LiveSeconds ###### UserId ###### SessionId #### SMTP 对象 说明:邮件发送对象,可派出出子类。 ##### 内容 - SMTP 对象的创建 - SMTP 对象的方法 - SMTP 对象属性 ##### SMTP 对象的创建 范例 ```text //范例1:创建smtp对象 Obj:= CreateObject("SMTP"); //范例2:根据配置创建smtp对象,配置写在\tinysoft\analyse.net\plugin\fileMgr.ini 文件 { [Smtp Settings] test:Port=25 test:UserName=name test:Password=password test=smtp.tinysoft.com.cn } obj:= CreateObject("smtp","test") ; echo obj.Authenticate();//验证账号密码是否正确。 return 1; ``` ##### SMTP 对象的方法 ###### 内容 - Login - SendCmd - Connect - Disconnect - DisconnectNotifyPeer - Send - Authenticate - QuickSend - Expand - Verify ###### Login ###### SendCmd 范例 ```text //发送HELO命令。 obj:= CreateObject("smtp") ; obj.Host := 'smtp.tinysoft.com.cn' ; obj.connect(); obj.sendcmd("HELO smtp.tinysoft.com.cn\r\n",r,c); return r; //结果:665518 Hello smtp.tinysoft.com.cn [ip], pleased to meet you. ``` ###### Connect 范例 ```text obj:= CreateObject("smtp") ; obj.Host := 'smtp.tinysoft.com.cn' ; obj.connect(); return 1; ``` ###### Disconnect 范例 ```text obj:= CreateObject("smtp") ; obj.Host := 'smtp.tinysoft.com.cn' ; obj.connect(); obj.disconnect(); return 1; ``` ###### DisconnectNotifyPeer 范例 ```text obj:= CreateObject("smtp") ; obj.Host := 'smtp.tinysoft.com.cn' ; obj.connect(); obj.DisconnectNotifyPeer(); return 1; ``` ###### Send 范例 ```text obj:= CreateObject("smtp") ; obj.UserName := 'username' ; //邮箱账号 obj.Password := 'password'; //邮箱密码 obj.Host := 'smtp.tinysoft.com.cn' ; //smtp地址 obj.port:=25; //端口 obj.connect(); //设置mailmsg对象 msg := CreateObject("MailMsg"); msg.subject := "SendMailTest"; //邮件标题 msg.body := "test"; //邮件内容 msg.Sender := "username@tinysoft.com.cn"; //邮件发送人邮箱 msg.Recipients :=" Recipients @qq.com";//邮件接收人邮箱 try obj.send(msg); except echo '\r\n邮件错误信息',obj.LastCmdResult(); return echo '\r\n邮件发送失败:',ExceptObject.errinfo; end; return 1; ``` 参考 MailMsg 对象 ###### Authenticate 范例 ```text obj:= CreateObject("smtp") ; obj.UserName := 'username' ; //邮箱账号 obj.Password := 'password'; //密码 obj.Host := 'smtp.tinysoft.com.cn' ; obj.port:=25; obj.connect(); return obj.Authenticate();//结果:1 ``` ###### QuickSend 范例 ```text obj := CreateObject("smtp"); obj.UserName := 'username'; //邮箱账号 obj.Password := 'password'; //邮箱密码 obj.Host := 'smtp.tinysoft.com.cn'; //smtp地址 obj.port := 25; //端口 obj.connect(); try mailHost:='smtp.tinysoft.com.cn'; //邮件服务器地址 mailSubject:="SendMailTest"; //邮件标题 mailBody := "test"; //邮件内容 mailSender := "username@tinysoft.com.cn"; //邮件发送人邮箱 mailRecipients := " Recipients@qq.com"; //邮件接收人邮箱 obj.QuickSend(mailHost,mailSubject,mailRecipients,mailSender,mailBody); except echo '\r\n邮件错误信息',obj.LastCmdResult(); return echo '\r\n邮件发送失败:',ExceptObject.errinfo; end; return 1; ``` ###### Expand ###### Verify 范例 ```text obj:= CreateObject("smtp","test") ; obj.Host := 'smtp.tinysoft.com.cn' ; obj.port:=25; try username:="username@tinysoft.com.cn"; return obj.verify(username); except return echo ExceptObject.errinfo; end; //结果:username < username@tinysoft.com.cn> ``` ##### SMTP 对象属性 ###### 内容 - AuthType - Host - Port - Username - Password - UseTLS - LastCmdResult - LastCmdResultCode - DidAuthenticate ###### AuthType ###### Host ###### Port ###### Username ###### Password ###### UseTLS ###### LastCmdResult ###### LastCmdResultCode ###### DidAuthenticate #### Pop3 对象 说明:Pop3 邮件处理对象。可派出出子类 ##### 内容 - Pop3 对象的创建 - Pop3 对象的方法 - Pop3 对象属性 ##### Pop3 对象的创建 范例 ```text //范例1:创建pop3对象 Obj:= CreateObject('POP3'); //范例2:根据配置创建pop3对象并自动连接登录,配置写在\tinysoft\analyse.net\plugin\fileMgr.ini 文件 { [CLASS:POP3] permit=local [POP3 Settings] test:Port=110 test:UserName=name test:Password=password test=pop3.tinysoft.com.cn } obj:= CreateObject("POP3","test","name","password") ; echo obj.CheckMessages();//若创建成功,则打印邮件数量 return 1; ``` ##### Pop3 对象的方法 使用范例: ```text ret:=CreateObject('PoP3','POP3.TINYSOFT.COM.CN',uName,passWord); ret.UIDL(ids); //取服务器的邮件唯一标示列表存放在ids中 s:= str2array(ids,'\r\n'); ss:=array(); for i:=0 to length(s)-2 do ss[i]:=str2array(s[i],' '); ss[:,0]:=strtoint(ss[:,0]); MsgID:=ss[3,0];//以第三个邮件为例 ret.Top(MsgID,r,10); //指定邮件内容前N行 echo '取邮件的前N行内容:',r[length(r)-40:]; d:=ret.RetrieveMsgSize(MsgID);//邮件大小 echo '邮件大小:',d; d1:=ret.RetrieveMailBoxSize();//邮箱大小 echo '邮箱大小:',d1; r1:=ret.Retrieve(MsgID,lr); //返回结果为MailMSg类型 echo '取邮件内容:',r1,' ',lr; echo tostn(ReturnMailMsg(lr)); r2:=ret.RetrieveHeader(MsgID,hr);//返回结果为MailMSg类型 echo '取邮件头部信息:',r2,' ',hr; echo tostn(ReturnMailMsg(hr)); r3:=ret.RetrieveHeader(MsgID,yr); //返回结果为MailMSg类型 echo '取邮件的原始内容:',r3,' ',yr; echo tostn(ReturnMailMsg(yr)); ss:=ret.CAPA(); echo '取服务器的支持命令列表:',ss; return ss; ``` 打印的信息截图:(只展示部分信息) ###### 内容 - Login - SendCmd - Connect - Disconnect - DisconnectNotifyPeer - CheckMessages - KeepAlive - Reset - Delete - Top - RetrieveMsgSize - RetrieveMailBoxSize - Retrieve - RetrieveHeader - RetrieveRaw - UIDL - CAPA ###### Login ###### SendCmd 范例 ```text ret:=CreateObject('PoP3','POP3.TINYSOFT.COM.CN',uName,password); r:=ret.SendCmd('UIDL 1',cr,rc);//获取指定邮件的唯一标识 return array(r,cr,rc); ``` 返回: ###### Connect 范例 ```text ret:=CreateObject('Pop3'); //通过属性设置后再连接 ret.Username:=uName; ret.Password:=passWord; ret.Host:='POP3.TINYSOFT.COM.CN'; ret.Port:=110; ret.UseTLS:=0; ret.Connect(); //连接邮箱服务器 return ret.CheckMessages(); ``` 返回: 406 ###### Disconnect ###### DisconnectNotifyPeer ###### CheckMessages 范例 ```text //登陆并返回邮箱中邮件数量 ret:=CreateObject('PoP3','POP3.TINYSOFT.COM.CN',uname,password); return ret.CheckMessages();//返回整数 ``` ###### KeepAlive ###### Reset ###### Delete ###### Top 范例 获取指定邮件前 3 行内容 ```text //创建pop3对象 pop3Obj := new pop3("pop3.tinysoft.com.cn","username","password"); ret := pop3Obj.Top(1,msg,3); if ret then return msg; else return "获取指定邮件前3行内容失败!"; ``` //结果: ###### RetrieveMsgSize 范例 获取指定邮件大小 ```text //创建pop3对象 pop3Obj := new pop3("pop3.tinysoft.com.cn","username","password"); return pop3Obj.RetrieveMsgSize(1); ``` //结果:18 ###### RetrieveMailBoxSize 范例 获取邮箱大小 ```text //创建pop3对象 pop3Obj := new pop3("pop3.tinysoft.com.cn","username","password"); return pop3Obj.RetrieveMailBoxSize(); ``` ###### Retrieve 范例 01:获取指定邮件内容 ```text //创建pop3对象 pop3Obj := new pop3("pop3.tinysoft.com.cn","username","password"); ret := pop3Obj.Retrieve(1,msg); if ret then return msg.asstring; else return "获取指定邮件内容失败!"; ``` //结果: ###### RetrieveHeader 范例 01:获取指定邮件头部信息 ```text //创建pop3对象 pop3Obj := new pop3("pop3.tinysoft.com.cn","username","password"); ret := pop3Obj.RetrieveHeader(1,msg); if ret then return msg.asstring; else return "获取指定邮件内容失败!"; ``` //结果: ###### RetrieveRaw 范例 01:获取指定邮件的原始内容 ```text //创建pop3对象 pop3Obj := new pop3("pop3.tinysoft.com.cn","username","password"); ret := pop3Obj.RetrieveRaw(1,msg); if ret then return msg; else return "获取指定邮件内容失败!"; ``` //结果: ###### UIDL 范例 ```text ret:=CreateObject('PoP3','POP3.TINYSOFT.COM.CN',uname,password); ret.UIDL(ids); //取服务器的邮件唯一标示列表存放在ids中 return ids; ``` 返回: (部分结果) 1 20220715095212230A 2 20220715142439001C 3 20220715151305015D 4 20220715182243051E 5 202207180708290CF7 6 20220718094652103B 7 20220718100236108E 8 2022071810050110AE … ###### CAPA 范例 获取邮件支持的所有命令 ```text //创建pop3对象 pop3Obj := new pop3("pop3.tinysoft.com.cn","username","password"); return := pop3Obj.CAPA(); ``` //结果: ##### Pop3 对象属性 ###### 内容 - AuthType - Host - Port - Username - Password - UseTLS - LastCmdResult - LastCmdResultCode - Capabilities - HasCAPA - HasAPOP - AutoLogin ###### AuthType ###### Host ###### Port ###### Username ###### Password ###### UseTLS ###### LastCmdResult ###### LastCmdResultCode ###### Capabilities ###### HasCAPA ###### HasAPOP ###### AutoLogin #### MailMsg 对象 邮件消息对象,用来 POP3 对象接收邮件或者 SMTP 对象发送邮件。辅助类,不能派出子类。 ##### 内容 - MailMsg 对象的创建 - MailMsg 对象的方法 - MailMsg 对象属性 ##### MailMsg 对象的创建 调用:CreateObject('MailMsg') ##### MailMsg 对象的方法 ###### 内容 - AddText - SendCmd - SaveToFile - LoadFromFile - SaveToStream - LoadFromStream - MessagePart - AddAttachment ###### AddText 参考 MessagePart 对象 ###### SendCmd ###### SaveToFile ###### LoadFromFile ###### SaveToStream ###### LoadFromStream ###### MessagePart 参考 MessagePart 对象 ###### AddAttachment 参考 MessagePart 对象 ##### MailMsg 对象属性 ###### 内容 - Flags - IsEncoded - MsgID - Headers - UID - IsMsgSinglePartMime - AttachmentEncoding - Body - BccList - CCList - CharSet - ContentType - ContentTransferEncoding - ContentDisposition - Date - Encoding - ExtraHeaders - FromList - From - NewsGroups - NoEncode - NoDecode - Organization - Priority - ReceiptRecipient - Recipients - References - InReplyTo - ReplyTo - Subject - Sender - UseNowForDate - LastGeneratedHeaders - ConvertPreamble - ExceptionOnBlockedAttachments - AttachmentTempDirectory - MessagePartsCount - AsString - AsBinary ###### Flags ###### IsEncoded ###### MsgID ###### Headers ###### UID ###### IsMsgSinglePartMime ###### AttachmentEncoding ###### Body ###### BccList ###### CCList - Flags - IsEncoded - MsgID - Headers - UID - IsMsgSinglePartMime - AttachmentEncoding - Body - BccList - CCList - CharSet - ContentType - ContentTransferEncoding - ContentDisposition - Date - Encoding - ExtraHeaders - FromList - From - NewsGroups - NoEncode - NoDecode - Organization - Priority - ReceiptRecipient - Recipients - References - InReplyTo - ReplyTo - Subject - Sender - UseNowForDate - LastGeneratedHeaders - ConvertPreamble - ExceptionOnBlockedAttachments - AttachmentTempDirectory - MessagePartsCount - AsString - AsBinary ###### CharSet ###### ContentType ###### ContentTransferEncoding ###### ContentDisposition ###### Date ###### Encoding - Flags - IsEncoded - MsgID - Headers - UID - IsMsgSinglePartMime - AttachmentEncoding - Body - BccList - CCList - CharSet - ContentType - ContentTransferEncoding - ContentDisposition - Date - Encoding - ExtraHeaders - FromList - From - NewsGroups - NoEncode - NoDecode - Organization - Priority - ReceiptRecipient - Recipients - References - InReplyTo - ReplyTo - Subject - Sender - UseNowForDate - LastGeneratedHeaders - ConvertPreamble - ExceptionOnBlockedAttachments - AttachmentTempDirectory - MessagePartsCount - AsString - AsBinary ###### ExtraHeaders ###### FromList ###### From - Flags - IsEncoded - MsgID - Headers - UID - IsMsgSinglePartMime - AttachmentEncoding - Body - BccList - CCList - CharSet - ContentType - ContentTransferEncoding - ContentDisposition - Date - Encoding - ExtraHeaders - FromList - From - NewsGroups - NoEncode - NoDecode - Organization - Priority - ReceiptRecipient - Recipients - References - InReplyTo - ReplyTo - Subject - Sender - UseNowForDate - LastGeneratedHeaders - ConvertPreamble - ExceptionOnBlockedAttachments - AttachmentTempDirectory - MessagePartsCount - AsString - AsBinary ###### NewsGroups ###### NoEncode ###### NoDecode ###### Organization ###### Priority ###### ReceiptRecipient ###### Recipients ###### References ###### InReplyTo ###### ReplyTo - Flags - IsEncoded - MsgID - Headers - UID - IsMsgSinglePartMime - AttachmentEncoding - Body - BccList - CCList - CharSet - ContentType - ContentTransferEncoding - ContentDisposition - Date - Encoding - ExtraHeaders - FromList - From - NewsGroups - NoEncode - NoDecode - Organization - Priority - ReceiptRecipient - Recipients - References - InReplyTo - ReplyTo - Subject - Sender - UseNowForDate - LastGeneratedHeaders - ConvertPreamble - ExceptionOnBlockedAttachments - AttachmentTempDirectory - MessagePartsCount - AsString - AsBinary ###### Subject ###### Sender ###### UseNowForDate ###### LastGeneratedHeaders ###### ConvertPreamble ###### ExceptionOnBlockedAttachments ###### AttachmentTempDirectory ###### MessagePartsCount ###### AsString ###### AsBinary #### MessagePart 对象 MesssagePart 是从属于 MailMsg 对象的消息部分。辅助类,不能派出子类。 ##### 内容 - MessagePart 对象的创建 - MessagePart 对象的方法 - MessagePart 对象属性 ##### MessagePart 对象的创建 调用:CreateObject('MessagePart')。 注:一般 MessagePart 无需主动创建,而是由 POP3 或者 NNTP 对象接收的 MailMsg 对象里自动创建,或者在 MailMsg 里调用 AddAttachment、AddText 方法来产生。 ##### MessagePart 对象的方法 ###### 内容 - SaveToFile - LoadFromFile - SaveToStream - LoadFromStream ###### SaveToFile ###### LoadFromFile ###### SaveToStream ###### LoadFromStream ##### MessagePart 对象属性 ###### 内容 - ContentType - IsEncoded - MsgID - Headers - CharSet - ExtraHeaders - ContentTransfer - ContentID - ContentDescription - ContentLocation - ParentPart - PartType - FileName - Body - AsString - AsBinary ###### ContentType ###### IsEncoded ###### MsgID ###### Headers ###### CharSet ###### ExtraHeaders ###### ContentTransfer ###### ContentID ###### ContentDescription ###### ContentLocation ###### ParentPart ###### PartType ###### FileName ###### Body ###### AsString ###### AsBinary