[转]delphi 变参函数:array of const

[转]delphi 变参函数:array of const

array of const

Delphi的Format函数大家都用得很多,第二个参数用着确实很方便。最近在数据库开发应用中需要自己创建一个带array of const参数的函数,对于常用的类型String,Integer,Pointer处理都没什么问题,但当用到Widestring类型时却出错,摸索了一上午,感觉获益良多。现在将问题、解决问题的思路、分析方法等一一道来,希望对诸君有所启发就达到了我写这篇文章的目的了! 
环境:Winxp + D7 
进入D7,在默认的新建工程中增加一过程Test(m: Array of const); 
procedure TForm1.test(m: array of const); 
var 
i, zero: Integer; 
s, t: String; 
c: Char; 
const 
sBoolean: Array [Boolean] of string = ('False', 'True'); 
begin 
s := ''; 
for i := 0 to High(m) do with m[i] do 
    case VType of    //写到这,按住Ctrl点击VType,打开System单元,将VType的枚举值贴到Case语句 
      vtInteger:    (VInteger: Integer; VType: Byte); 
      vtBoolean:    (VBoolean: Boolean); 
      vtChar:       (VChar: Char); 
      vtExtended:   (VExtended: PExtended); 
      vtString:     (VString: PShortString); 
      vtPointer:    (VPointer: Pointer); 
      vtPChar:      (VPChar: PChar); 
      vtObject:     (VObject: TObject); 
      vtClass:      (VClass: TClass); 
      vtWideChar:   (VWideChar: WideChar); 
      vtPWideChar: (VPWideChar: PWideChar); 
      vtAnsiString: (VAnsiString: Pointer); 
      vtCurrency:   (VCurrency: PCurrency); 
      vtVariant:    (VVariant: PVariant); 
      vtInterface: (VInterface: Pointer); 
      vtWideString: (VWideString: Pointer); 
      vtInt64:      (VInt64: PInt64); 
    end; 
Delete(s, 1, 1); 
Self.Caption := s; 
end; 
继续写,对各枚举值进行处理!这里作一下解释,Array of const正是由TVarRec类型组成的! 
请看Case of语句中的代码: 
      vtInteger: s := s + ';' + IntToStr(VInteger); 
      vtBoolean: s := s + ';' + sBoolean[VBoolean]; 
      vtChar: s := s + ';' + VChar; 
      vtExtended: s := s + ';' + FloatToStr(VExtended^); 
      vtString: 
        if Assigned(VString) then begin 
          t := VString^; 
          s := s + ';' + t; 
        end; 
      vtPointer: 
        if Assigned(VPointer) then 
          s := Format('%S; Pointer: $%X ',[s, Integer(VPointer)]); 
      vtPChar: 
        if Assigned(VPChar) then begin 
          t := VPChar^; 
          s := s + ';' + t; 
        end; 
      vtObject: 
        if Assigned(VObject) then 
          s := Format('%S; $%X ClassName: %S ',[s, Integer(@VObject), VObject.ClassName]); 
      vtClass: 
        if Assigned(VClass) then 
          s := Format('%S; Class Reference $%X - ClassName: %S ',[s, Integer(VClass), VClass.ClassName]); 
      vtWideChar: 
        begin 
          t := VWideChar; 
          s := s + ';' + t; 
        end; 
      vtPWideChar: 
        if Assigned(VPWideChar) then begin 
          t := VPWideChar^; 
          s := s + ';' + t; 
        end; 
      vtAnsiString: 
        if Assigned(VAnsiString) then begin 
          t := PChar(VAnsiString); 
          s := s + ';' + t; 
        end; 
      vtCurrency: 
        if Assigned(VCurrency) then 
          s := s + ';' + FloatToStr(VCurrency^); 
      vtVariant: 
        if Assigned(VVariant) then 
          s := s + '; This is variant '; 
      vtInterface: 
        if Assigned(VInterface) then 
          s := Format('%S; Interface: $%X',[s, Integer(VInterface)]); 
      vtWideString: 
        if Assigned(VWideString) then begin 
          t := PWideString(VWideString)^; 
          s := s + ';' + t; 
        end; 
      vtInt64: 
        if Assigned(VInt64) then 
          s := s + ';' + IntToStr(VInt64^);


加上一按钮测试该函数 
procedure TForm1.Button1Click(Sender: TObject); 
var 
ws: WideString; 
begin 
ws := 'dda这是一个测试dfa'; 
test([self, 'sdf', 2.3324, ws, TForm]); 
end;


可以看到测试结果,变量ws的值没有显示出来,怎么办呢? 
我们可以看到WideString类型的值是指针,我们就从这里着手,在事件中添加一句: 
Button1.Caption := Format('$%X',[Integer(@ws)]); 
此句的作用是显示出ws的地址 
再在Test函数中也加上类似的语句,并注释掉无用的语句: 
//t := PWideString(VWideString)^; 
//s := s + ';' + t; 
s := s + ';' + Format('$%X',[Integer(VWideString)]); 
运行可看到二个地址不一样,说明Delphi对传入的参数数据作了复制 
因此将其强制转换成PWidechar应该可以,增加一变量声明 
w: WideString; 
w := PWideString(VWideString)^; 
s := s + ';' + w; 
但运行结果却只显示一个字符,别沮丧,已经摸到门道了! 
我们知道Format可以处理Widestring类型,这里只得到一个字符,说明字符被截断了。Delphi中的字符串是以#0结束,Widestring以二个#0结束,可以肯定w := PWideString(VWideString)^这句Delphi作转换时肯定将其默认作为AnsiString处理了。分析到这里已经可动手写下去了..... 
p: PByte; 
        if Assigned(VWideString) then begin 
          t := ''; 
          zero := 0; 
          p := VWideString; 
          repeat 
            c := char(p^); 
            inc(p); 
            if c = #0 then 
              inc(zero) else 
              begin 
                zero := 0; 
                t := t + c; 
              end; 
          until zero = 2; 
          s := s + ';' + t; 
        end; 
但是显示汉字却变成乱码了,而且处理也显得臃肿。到这里我们已经明白了,VWideString所指示的字符串是二字节宽字符串,而且Intel的字节顺序也是低位在前,高位在后。因此可用PWord进行处理! 
删除c,zero,w变量,p改成: 
p: PWord; 
        if Assigned(VWideString) then begin 
          t := ''; 
          p := VWideString; 
          repeat 
            t := t + widechar(p^); 
            inc(p); 
          until p^ = 0; 
          s := s + ';' + t; 
        end; 
可以看到核心代码已经很精练了,运行已经显示正常,汉字也无乱码了!至此我们似乎是大功告成了,但静下来想想,Delphi支持WideString到String的转换,它也应该有这样的处理代码。 
而且在循环中t := t + widechar(p^);语句处下一断点,运行到断点处,再打开CPU窗口,看到看似简洁的代码,单此一句,编译器都要给它加上一大堆处理代码。找到系统的字符串处理函数很有必要,经过在System.pas单元中搜索WideString,找到函数:procedure WideCharToStrVar(Source: PWideChar; var Dest: string); 
呵呵,这正是我们要的!!! 
现在循环语句及P变量都可删除了,代码我就省略了。

function   MakeStr(const   Args:   array   of   const):   string;   
  const   
      BoolChars:   array[Boolean]   of   Char   =   ('F',   'T');   
  var   
      I:   Integer;   
  begin   
      Result   :=   '';   
      for   I   :=   0   to   High(Args)   do   
          with   Args[I]   do   
              case   VType   of   
                  vtInteger:         Result   :=   Result   +   IntToStr(VInteger);   
                  vtBoolean:         Result   :=   Result   +   BoolChars[VBoolean];   
                  vtChar:               Result   :=   Result   +   VChar;   
                  vtExtended:       Result   :=   Result   +   FloatToStr(VExtended^);   
                  vtString:           Result   :=   Result   +   VString^;   
                  vtPChar:             Result   :=   Result   +   VPChar;   
                  vtObject:           Result   :=   Result   +   VObject.ClassName;   
                  vtClass:             Result   :=   Result   +   VClass.ClassName;   
                  vtAnsiString:   Result   :=   Result   +   string(VAnsiString);   
                  vtCurrency:       Result   :=   Result   +   CurrToStr(VCurrency^);   
                  vtVariant:         Result   :=   Result   +   string(VVariant^);   
                  vtInt64:             Result   :=   Result   +   IntToStr(VInt64^);   
          end;   
  end;  


  We can call this function using an open array constructor   (see Open   array   constructors).  

  For   example,   
  MakeStr(['test',   100,   '   ',   True,   3.14159,   TForm])   
  returns   the   string   "test100   T3.14159TForm".

« 博主上一篇: [转]Delphi过程函数传递参数的几种方式
» 博主下一篇: [转]QR代码(Quick Response Code)简介
procedure TForm1.Test(m: array of const);
var 
i, zero: Integer; 
s, t: String; 
c: Char; 
const 
sBoolean: Array [Boolean] of string = ('False', 'True');
begin 
s := ''; 
for i := 0 to High(m) do with m[i] do 
    case VType of    //写到这,按住Ctrl点击VType,打开System单元,将VType的枚举值贴到Case语句 
     { vtInteger:    (VInteger: Integer; VType: Byte);
      vtBoolean:    (VBoolean: Boolean); 
      vtChar:       (VChar: Char); 
      vtExtended:   (VExtended: PExtended); 
      vtString:     (VString: PShortString); 
      vtPointer:    (VPointer: Pointer); 
      vtPChar:      (VPChar: PChar); 
      vtObject:     (VObject: TObject); 
      vtClass:      (VClass: TClass); 
      vtWideChar:   (VWideChar: WideChar); 
      vtPWideChar: (VPWideChar: PWideChar); 
      vtAnsiString: (VAnsiString: Pointer); 
      vtCurrency:   (VCurrency: PCurrency); 
      vtVariant:    (VVariant: PVariant); 
      vtInterface: (VInterface: Pointer); 
      vtWideString: (VWideString: Pointer); 
      vtInt64:      (VInt64: PInt64);
      }
      vtInteger: s := s + ';' + IntToStr(VInteger); 
      vtBoolean: s := s + ';' + sBoolean[VBoolean]; 
      vtChar: s := s + ';' + VChar; 
      vtExtended: s := s + ';' + FloatToStr(VExtended^); 
      vtString: 
        if Assigned(VString) then begin 
          t := VString^; 
          s := s + ';' + t; 
        end; 
      vtPointer: 
        if Assigned(VPointer) then 
          s := Format('%S; Pointer: $%X ',[s, Integer(VPointer)]); 
      vtPChar: 
        if Assigned(VPChar) then begin 
          t := VPChar^; 
          s := s + ';' + t; 
        end; 
      vtObject: 
        if Assigned(VObject) then 
          s := Format('%S; $%X ClassName: %S ',[s, Integer(@VObject), VObject.ClassName]); 
      vtClass: 
        if Assigned(VClass) then 
          s := Format('%S; Class Reference $%X - ClassName: %S ',[s, Integer(VClass), VClass.ClassName]); 
      vtWideChar: 
        begin 
          t := VWideChar; 
          s := s + ';' + t; 
        end; 
      vtPWideChar: 
        if Assigned(VPWideChar) then begin 
          t := VPWideChar^; 
          s := s + ';' + t; 
        end; 
      vtAnsiString: 
        if Assigned(VAnsiString) then begin 
          t := PChar(VAnsiString); 
          s := s + ';' + t; 
        end; 
      vtCurrency: 
        if Assigned(VCurrency) then 
          s := s + ';' + FloatToStr(VCurrency^); 
      vtVariant: 
        if Assigned(VVariant) then 
          s := s + '; This is variant '; 
      vtInterface: 
        if Assigned(VInterface) then 
          s := Format('%S; Interface: $%X',[s, Integer(VInterface)]); 
      vtWideString: 
        if Assigned(VWideString) then begin 
          t := PWideString(VWideString)^; 
          s := s + ';' + t; 
        end; 
      vtInt64: 
        if Assigned(VInt64) then 
          s := s + ';' + IntToStr(VInt64^);
    end; 
Delete(s, 1, 1); 
Self.Caption := s; 
end;

procedure TForm1.Button5Click(Sender: TObject);
var
ws: WideString; 
begin 
ws := 'dda这是一个测试dfa';
test([self, 'sdf', 2.3324, ws, TForm]);
end;


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值