您好,欢迎来到客趣旅游网。
搜索
您的当前位置:首页delphivariant变量的使用技巧

delphivariant变量的使用技巧

来源:客趣旅游网
少年易学老难成,一寸光阴不可轻 -

DELPHI Variant变量的使用技巧。。。。。。

delphi 为了完全支持OLE,32位Delphi 增加了Variant 数据类型,本节将从宏观角度来分析这种数据类型。实际上,Variant类型对Pascal语言有普遍而深入的影响,Delphi 控件库中与OLE 无关的地方也使用到这种类型。

Variant变量没有类型

一般说来,你可以用Variant 变量存储任何数据类型,对它执行各种操作和类型转换。需要注意的是:这违反了Pascal 语言的一贯原则,有悖于良好的编程习惯。variant 变量的类型检查和计算在运行期间才进行,编译器不会提示代码中的潜在错误,这些错误在进一步测试中才能发现。总之,你可以认为包含variant变量的代码是解释性代码,正如解释性代码一样,许多操作直到执行时才能知道,这对代码运行速度会有很大的影响。

上面对Variant 类型的使用提出了警告,现在来看看Variant 类型究竟能干什么。基本上说,如果声明了一个variant 变量:

var V: Variant;

你就可以把各种不同类型的值赋给它:

V := 10;

V := 'Hello, World'; V := 45.55;

一旦得到一个variant 值,你可以把它拷贝给任何兼容或不兼容的数据类型。如果你把值赋给不兼容的数据类型,Delphi 会力尽所能进行转换,无法转换则颁布一个运行时间错误。实际上,variant变量中不仅包含了数据还包含有类型信息,并允许一系列运行时间操作,这些操作很方便,但运行速度慢且安全性差。

见例VariTest,它是上面代码的扩展。窗体上有三个编辑框,一对按钮,第一个按钮的OnClick 事件代码如下:

procedure TForm1.Button1Click(Sender: TObject); var V: Variant; begin V := 10;

1

少年易学老难成,一寸光阴不可轻 -

Edit1.Text := V; V := 'Hello, World'; Edit2.Text := V; V := 45.55; Edit3.Text := V; end;

很有趣是不是?你可以把一个值为字符串的variant 变量赋给编辑框Text 属性,还可以把值为整数或浮点数的variant 变量赋给Text属性。正如你在图10.1中所看到的,一切正常。

(图10.1)按Assign按钮后,例VariTest的输出结果

图 10.1: 例 VariTest 的 Assign 按钮 Click 事件输出结果

更糟糕的是:你还可以用variant变量计算数值,从第二个按钮的Click事件代码就可看到这一点:

procedure TForm1.Button2Click(Sender: TObject); var V: Variant; N: Integer; begin

V := Edit1.Text; N := Integer(V) * 2; V := N; Edit1.Text := V; end;

至少这种代码带有一定危险性,如果第一个编辑框包含了一个数字,那么一切运行正常;如果不是,将会引发异常。这里再重申一遍,如果不到万不得以,不要随便使用Variant 类型,还是应坚持使用传统的Pascal 数据类型和类型检查方法。在Delphi 和 VCL中,variant变量主要是用于 OLE 支持和数据库域的访问。

2

少年易学老难成,一寸光阴不可轻 -

Variant类型内部结构

Delphi中定义了一个 variant 记录类型,TVarData,它与Variant 类型有相同的内存布局。你可以通过TVarData访问variant变量的实际类型。TVarData 结构中包含了Variant类型信息(由Vtype域表示)、一些保留域及当前值。

VType域的取值包括OLE 自动化中的所有数据类型,这些类型通常叫OLE 类型或variant 类型。以下是variant 类型的完整列表,按字母顺序排列:

varArray varBoolean varByRef varCurrency varDate varDispatch varDouble varEmpty varError varInteger varNull varOleStr varSingle varSmallint varString varTypeMask varUnknown varVariant

3

少年易学老难成,一寸光阴不可轻 -

你可以在Delphi 帮助系统的variants 主题下找到这些类型的说明。

还有许多操作variant 变量的函数,你可以用它们进行特定的类型转换,或通过它们获取variant变量的类型信息(例如VarType 函数),当你用variant变量写表达式时,Delphi会自动调用这些类型转换和赋值函数。另外还有操作variant 数组的例程,你可以通过帮助文件的Variant support routines 主题了解相关内容。

Variant类型运行很慢!

Variant 类型代码运行很慢,不仅数据类型转换如此,两个值为整数的Variant 变量相加也是如此。它们几乎跟Visual Basic这种解释性代码一样慢!为了比较Variant变量和整型变量的运行速度,请看例VSpeed 。

程序中设置了一个循环,记录运行时间并在进程条中显示运行状态。下面是基于variant类型的一段代码,基于整型的代码与此相似:

procedure TForm1.Button1Click(Sender: TObject); var

time1, time2: TDateTime; n1, n2: Variant; begin time1 := Now; n1 := 0; n2 := 0;

ProgressBar1.Position := 0; while n1 < 5000000 do begin n2 := n2 + n1; Inc (n1);

if (n1 mod 50000) = 0 then begin

ProgressBar1.Position := n1 div 50000;

4

少年易学老难成,一寸光阴不可轻 -

Application.ProcessMessages; end; end;

// we must use the result Total := n2; time2 := Now;

Label1.Caption := FormatDateTime ( 'n:ss', Time2-Time1) + ' seconds'; end;

记时这段代码值得一看,因为你可以把它用到任何类型的性能测试中。正如你所看到的,程序用Now 函数获取当前的时间,用FormatDateTime 函数格式化时间差,输出结果以分(\"n\")和秒(\"ss\")表示。除此之外,你可以用Windows API的GetTickCount 函数,该函数能精确显示操作系统启动后至当前的毫秒数。

从上例可见两者的速度差异非常之大,以至于不用精确记时也能看到这种差异。图10.2是在本人计算机上运行程序看到的结果。当然运行结果取决于运行程序的计算机,但是两者的数值比不会有太大变化。

Delphi笔记(整理)-变体

博客分类:

学习笔记

Delphi数据结构J#

除结构类型和指针外,变体类型能存储其它的任何类型;

变体类型能存储接口,并能通过它使用接口的方法和属性(参考Object interfaces); 变体类型能存储动态数组,也能存储一种特殊的静态数组:变体数组(Variant array)。

变体类型能和其它变体类型、整数、实数、字符串和布尔值在表达式和赋值语句中混合使用,编译器自动完成类型转换。

5

少年易学老难成,一寸光阴不可轻 -

可以通过自定义来扩展变体类型,从而能存储任意值。比如,你可以定义一个使用索引的变体字符串 类型,或者让它存储特定的类引用、记录或静态数组。自定义变体类型通过TCustomVariantTyp 的子类 来创建。

所有的变体类型在创建时被初始化为Unassigned,Null 表示未知或没有数据。

赋空值: Var

标准函数VarType 返回变体类型的类型码,常量varTypeMask 是一个位掩码,用来从VarType 的返回值 中提取类型码,所以,在下面的例子中 VarType(V) and varTypeMask = varDouble

若V 包含Double 或Double 数组,则它返回True

在System 单元定义的TVarData 记录类型能被用来转换变体类型,并且可以访问它们的内部构造。

VarAsType 和VarCast 标准例程能用来改变一个Variant 的内部表示。

除了^、is 和in,所有运算符都可以使用Variant 作为运算数

对Variant 的操作返回Variant 值;若有一个运算数是Null 则结果为Null; 若有一个运算数为Unassigned 则引发异常。

在二元运算中,若只有一个运算数是Variant,则另一个被转换为Variant。

不能把一个普通的静态数组赋给Variant,取而代之的是,通过调用VarArrayCreate 或VarArrayOf 两者 之一来创建Variant 数组。比如, V: Variant; ...

V := VarArrayCreate([0,9], varInteger);

要创建字符串类型的Variant 数组,使用varOleStr

使用VarArrayRedim 函数来更改Variant 数组的大小。其它用于Variant 数组的标准例程包括

VarArrayDimCount 、VarArrayLowBound 、VarArrayHighBound 、VarArrayRef 、VarArrayLock 和VarArrayUnlock.

。Variant 和OleVariant 的主要区别是,Variant 能包含只有当前程序才能理解的数据类型,

OleVariant 只包含为Ole 自动化兼容而定义的数据类型,它说明,这些数据类型能在程序间或通过网络传送, 而不必担心另一端是否知道如何处理它们。 type T1 = Integer; T2 = T1;

V:Variant; v:=vaNil;

6

少年易学老难成,一寸光阴不可轻 -

T3 = Integer; T4 = T2;

T1、T2、T3、T4 和Integer 都是指的同一种类型。要声明一种不同的类型,在声明中重复type 关键字。 比如

type TMyInteger = type Integer;

创建了一种新类型TmyInteger,它和Integer 不同。

一个类型声明指定一个标志符,来表示一种数据类型。类型声明的语法为 type newTypeName = type

这里,newTypeName 是一个有效的标志符。比如,给定如下的类型声明 type TMyString = string; 你就可以声明变量 var S: TMyString;

同时声明多个变量时不能包括初始化,Variant 和文件类型的变量声明也不能初始化。

如果你没有明确地初始化一个全局变量,编译器把它初始化为0。相反,不能在声明局部变量时进行初 始化,它们的值是随机的,直到赋给它们一个值。

你可以创建一个新变量,它和另一个变量在内存的同一个位置。要这样做的话,声明这个新变量时在类 型名的后面跟关键字absolute,后面再跟一个已存在(先前声明)的变量。比如, var

Str: string[32];

StrLen: Byte absolute Str;

指定变量StrLen 从Str 的地址开始。因为短字符串的第一个字节包含字符串的长度,StrLen 的值就是Str 的长度。

使用absolute 声明时不能初始化变量,也不能组合其它指示字(和absolute 一同使用)。

可以调用GetMem 或New 过程来创建动态变量,这种变量在堆中分配内存,它们不能自动管理。 使用FreeMem 来释放由GetMem 创建的变量,使用Dispose 释放由New 创建的变量。

其它能作用于动态变量的标准例程包括ReallocMem、Initialize、StrAlloc 和StrDispose。

声明线程局部变量时,使用threadvar,而不是var,比如, threadvar X: Integer; 线程变量声明

• 不能出现在过程或函数中 • 不能包含初始化

• 不能指定absolute 指示字

不能创建指针或过程类型的线程变量,也不能在动态调入库中使用线程变量(除了包)。

由编译器管理的动态变量,即长字符串、宽字符串、动态数组、Variants 和接口,能被声明为threadvar, 但编译器不能自动释放由每个线程创建的堆内存。若使用这些类型的线程变量,要负责释放它们的内存。

资源字符串的声明像真常量,除了用resourcestring 代替const。表达式等号的右边必须是常量表达式并

7

少年易学老难成,一寸光阴不可轻 -

且返回一个字符串。

在默认的{$J-}编译状态下,类型常量不能被赋予新值,实际上,它们是只读变量;但如果使用了{$J+} 编译器指示字,类型常量能被赋予新值,它们在本质上就像初始化的变量。

要声明数组常量,把数组元素的值用括号括起来,值之间用逗号隔开,这些值必须是常量表达式。比如, const Digits: array[0..9] of Char = (’0’, ’1’, ’2’, ’3’, ’4’, ’5’, ’6’, ’7’, ’8’, ’9’); 上面的声明可以方便地表示为

const Digits: array[0..9] of Char = ’01234567’;

要声明一个记录常量,在括号中使用fieldName: value 的形式来指定每个字段的值,每个字段用分号隔开。 每个字段的值必须是常量表达式。字段列出的顺序必须和声明的相同,若有tag 字段,则必须指定它的 值;若记录有一个Variant 部分,只有tag 字段选定的Variant 才能被赋值。 举例如下: type

TPoint = record X, Y: Single; end;

TVector = array[0..1] of TPoint;

TMonth = (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec); TDate = record D: 1..31; M: TMonth; Y: 1900..1999; end; const

Origin: TPoint = (X: 0.0; Y: 0.0);

Line: TVector = ((X: -3.1; Y: 1.5), (X: 5.8; Y: 3.0)); SomeDay: TDate = (D: 2; M: Dec; Y: 1960); 记录常量不能包含文件类型的值。

8

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- kqyc.cn 版权所有 赣ICP备2024042808号-2

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务