新時代的開端:DELPHI.NET- 語言篇

新時代的開端:DELPHI.NET- 語言篇

新時代的開端:DELPHI.NET- 語言篇
文/黃忠成(2004/1/1,原文刊登於PC 電腦傳真月刊)
DELPHI.NET
在經過近兩年的漫長等待後,Borland 終於在2003 年的耶誕前夕釋出了DELPHI 8
for .NET Framework 的正式版本,此舉不但粉碎了DELPHI 已死的揣測,也正式將DELPHI
使用者帶入了.NET 的世界。藉由VCL.NET,原DELPHI 使用者可以延用以往所開發的
元件或是程式,用幾乎相同的方式撰寫.NET Windows Application。除此之外,
DELPHI.NET 也支援.NET WinForm 及ASP.NET 的應用程式開發,這就像是DELPHI 一
貫的傳統:支援最多的環境,提供多樣化的開發技術,讓使用者得到最大的應用空間。
當然,不可否認,DELPHI.NET 畢竟是一個新的開發環境及一個加強後的DELPHI 語言,
要說完全無痛升級是不可能的,程式設計師應該要有一個認知,在Windows 時代,API
是不可缺的知識,在今日的.NET 時代也不例外,了解.NET Framework 是基本的要求。
針對DELPHI.NET 所提供的各種新功能及新語言特色,筆者規畫了一系列文章,希望
能幫助原DELPHI 的使用者快速的進入DELPHI.NET 的世界,現在就讓我們開始這一趟
旅程吧。
Imporved! Namespace(命名空間)
事實上,Namespace 並非是在DELPHI.NET 中第一次出現,早在DELPHI 時代就已具
備基本的Namespace 概念,只是當時此技術尚未成熟,大多數時候只是用來解決模糊呼
叫或是定義等問題,下面的程式碼片段是在DELPHI 時代使用該技術的範例。
Dialogs.ShowMessage(AMsg);
當時,這種技術頂多只能稱之為Unit 的分割,離真正的Namespace 尚有段距離。為了
符合CLS 規格,DELPHI.NET 加入了真正的Namespace 機制,使編譯後的Assembly 能
為其它CLS 相容語言所用,其基本用法與以往大致相同。
unit MyCompany.MyProduct.Unit2;
interface
uses Borland.Vcl.Classes,Borland.Vcl.SysUtils;
與DELPHI 相同,DELPHI.NET 的Unit 檔名需與unit ...部份同名,另外原先的Classes、
SysUtils 等Unit 也都納入了Borland.Vcl 這個Namespace 之中,不過使用者並不需特別
修改以往的程式來符合這個改變,藉由編譯器預設Namespace 搜尋功能,使用者仍可使
用uses Classes,SysUtils 方式來處理,編譯器自會代為轉換。提醒讀者,目前DELPHI.NET
仍只支援在一個Unit 中定義單一Namespace,並不允許同一Unit 擁有多個Namespace。
另外DELPHI.NET Unit 也不支援類似C#等語言中以明確定義代替uses 的方式,簡單的
說就是要引用Unit2 才能使用其中的定義,不能省略掉引用Unit2 部份,直接使用
Unit2.xxx 方式宣告。
New! 成員視界
在DELPHI.NET 中,除了原有的private、protected、public、published 四個視界外,還
加入了strict private、strict protected 兩個新的成員視界,此舉是為了符合CLS 規格。原先
的DELPHI 中,private、protected 在同一Unit 中是被視同為public 視界的,下面的程式碼
說明了此點。
type
TMyClass = class
private
FData:Integer;
end;
...............
vObj := TMyClass.Create;
vObj.FData := 100; //OK!
這個特性仍被延用至DELPHI.NET,事實上它們被對應至Assembly or Family、Assembly
and Family 兩個CLS 所規範的視界,而strict private 及strict protected 則對應到真實的
private、protected 兩個視界,表一列出目前DELPHI.NET 的視界對應及存取限制。
TMyClass = class
strict private
FPrivateData:Integer;
private
FData:Integer;
end;
.............
vObj := TMyClass.Create;
vObj.FData := 100; //OK
vObj.FPrivateData := 100; //Error
DELPHI.NET C# CLS 說明
private internal Assembly 該類別或同一Assembly 才可存取。
protected internal protected Assembly or Family 同一Assembly 或子類別才可存取。
public public Public 不限。
strict private private Private 該類別中才可存取。
strict protected protected Family 該類別及其子類別才可存取。
New! class var(靜態成員變數)
對DELPHI 使用者來說,靜態成員變數是個新功能,以往多是以全域變數來達到相同
效果,使用靜態成員可以有效的將設計師由全域變數的窠臼中解放。
TMyClass = class(TObject)
class var
InstanceCount:Integer;
..................
constructor TMyClass.Create;
begin
TMyClass.InstanceCount := TMyClass.InstanceCount+1;
inherited Create;
end;
destructor TMyClass.Destroy;
begin
TMyClass.InstanceCount := TMyClass.InstanceCount-1;
inherited Destroy;
end;
..................
TMyClass.Create;
TMyClass.Create;
TMyClass.Create;
ShowMessage(IntToStr(TMyClass.InstanceCount)); // 3.
class var 與一般成員相同,也具備了視界的觀念。
New! static member function(靜態成員函式)
事實上,DELPHI 中早就具備了靜態成員函式的功能,當時稱為class method,
DELPHI.NET 除了繼續延用此概念外,還加入了static method 的支援,這點主要是針對
CLS 的規格而定。但是目前On-Line Help 在描述語法時似乎有誤,其內的範例是在一般
的method 後加上static 即可成為靜態成員函式,但實際上編譯器並不接受此語法,在筆
者觀察VCL 的原始碼後,正確的用法應該如下所示。
TMyClass = class(TObject)
class var
InstanceCount:Integer;
public
...............
class procedure ShowInstanceCount; static;
end;
class procedure 是否加上static 的關鍵字,會影響編譯器所產生的IL 程式碼,假如設計
者希望該函式能為其它CLS 相容語言所用,就必須加上static 關鍵字。
New! static properties(靜態成員屬性)
這也是一個全新的功能,DELPHI.NET 允許設計師定義靜態的成員屬性,其唯一限制
是在屬性的存取函式或是變數都必須是靜態成員。
TMyClass = class(TObject)
strict private
class procedure SetData(AData:Integer);static;
class function GetData:Integer;static;
class var
FData : Integer;
public
class property Data:Integer read GetData write SetData;
end;
.........
TMyClass.Data := 100;
ShowMessage(IntToStr(TMyClass.Data)); //100
New! static construtcor(靜態建構子)
在DELLPHI.NET 中,靜態建構子(class constructor)可用來初使化靜態成員。
TMyClass = class(TObject)
class var
FDataVar : Integer;
public
class constructor Create;
end;
..............
class constructor TMyClass.Create;
begin
FDataVar := 1000;
end;
......
ShowMessage(IntToStr(TMyClass.FDataVar)); // 1000
基本上,DELPHI.NET 提供了完整的靜態成員支援,而其是由原本的class member 所延
伸而來。
New! Nested Type(巢狀型別)
這也是為了符合CLS 所添加的新功能,DELPHI.NET 允許設計師在某個類別中定義
一個子類別,需注意的一點是DELPHI.NET 的Nested Type 並不受視界影響,即使將子
類別宣告於strict private 之中,實際上所編譯出來的仍然是public。不過設計師仍可延用
以往將類別宣告於implementation 區段後的方式來達到與private 相同效果。
TMyClass = class(TObject)
public
type
TMyClassInner = class(TObject)
public
FData:Integer;
end;
strict private
FInner : TMyClassInner;
.....................
var
vObj2 : TMyClass.TMyClassInner;
begin
vObj2 := TMyClass.TMyClassInner.Create;
..................
New! Sealed Classes(末代類別)
在CLS 規格中允許設計者定義一個seled class,此種類別將不支援繼承,DELPHI.NET
同時也支援了此功能。不過,DELPHI.NET 的on-line help 對此語法的描述是錯誤的,
下面是正確的語法。
TMyClass = class sealed
public
procedure HelloMyClass;
end;
TMyClass2 = class(TMyClass) //Error!
New! Operator Overload(運算子覆載)
運算子覆載對於DELPHI 設計師來說是一個完全嶄新的概念,藉由此功能的幫助,設
計師可以自定類別的運算子行為,提供使用者一個較直覺的應用模式,例如用”+”符號
直接加總兩個物件實體,或是改變物件的型別轉換行為,下面的程式展現了此類運用。
TMyClass = class
strict private
FData:Integer;
public
class operator Add(A,B:TMyClass):TMyClass;
class operator Implicit(A:Integer):TMyClass;
class operator Implicit(A:TMyClass):Integer;
property Data:Integer read FData write FData;
end;
...................
class operator TMyClass.Add(A,B:TMyClass):TMyClass;
begin
Result := TMyClass.Create;
Result.Data := A.Data + B.Data;
end;
class operator TMyClass.Implicit(A:Integer):TMyClass;
begin
Result := TMyClass.Create;
Result.Data := A;
end;
class operator TMyClass.Implicit(A:TMyClass):Integer;
begin
Result := A.Data;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
vObj1,vObj2,vResult,vResult2:TMyClass;
vInt:Integer;
begin
vObj1 := TMyClass.Create;
vObj2 := TMyClass.Create;
vObj1.Data := 100;
vObj2.Data := 100;
vResult := vObj1 + vObj2;
ShowMessage(IntToStr(vResult.Data));
vInt := vResult;
ShowMessage(IntToStr(vInt));
vResult2 := vInt;
ShowMessage(IntToStr(vResult2.Data));
end;
程式中只展示了隱含轉型的覆載,DELPHI.NET 也支援明確轉型的覆載,只要將Implicit
改為Explicit 即可。DELPHI.NET 的運算子覆載技術完全相容於CLS 規格,其它支援運
算子覆載的CLS 語言,如C# 皆可直接引用。不過設計師為此特色興奮之餘,也不能忘
記一點,運算子覆載是個相當嚴肅的課題,當覆載了”+”符號之後,若不覆載其它運算
符號,將令使用者感到困惑,這也是運算子覆載容易造成錯誤的原因。
New! class helper
這不僅是一個全新的功能,同時也是一個嶄新的概念,DELPHI.NET 為了達到整合
VCL.NET 與.NET Framework 的目的,加入了class helper 功能,運用此功能,設計者可
以在不改變既存類別原始設計的方式,延伸該類別,即使該類別是末代類別也不例外,
下面是一個簡單的範例。
TMyClass = class sealed
public
procedure HelloMyClass;
end;
TMyClassHelper = class helper for TMyClass
public
procedure HelloMyClassHelper;
end;
..........
procedure TMyClass.HelloMyClass;
begin
ShowMessage('Hello My Class!');
end;
procedure TMyClassHelper.HelloMyClassHelper;
begin
ShowMessage('Hello My Class Helper!');
end;
...............
var
vObj : TMyClass;
begin
vObj := TMyClass.Create;
vObj.HelloMyClass;
vObj.HelloMyClassHelper;
end;
熟悉Design Patterns 的讀者應該已發現,class helper 有點類似Adapter 及Helper 這兩個
Pattern,是的!基本上class helper 就是這兩個Pattern 的演化,只是DELPHI.NET 採取編
譯器角度來實作,並將細節隱藏。class helper 也支援繼承與虛擬函式的操作,這代表著
class helper 開啟了除繼承外的另一扇延伸之窗,下面的範例展示了此種用法。
TMyClassHelper = class helper for TMyClass
public
procedure HelloMyClassHelper;virtual;
end;
TMyClassHelper2 = class helper(TMyClassHelper) for TMyClass
public
procedure HelloMyClassHelper;override;
end;
需特別注意的一點,因為class helper 的實作方式較一般class 不同,因此不支援strict
private、strict protected 這兩個視界,同時也不能擁有成員變數,只允許靜態成員變數。
class helper 底層運作
相信有些讀者一定對於class helper 內部的實作方式很好奇,筆者也是,所以利用了
ILDASM 及DeCompiler 工具來觀察使用class helper 類別的實作,事實上,class helper
最終的實作碼大致與下面的DELPHI 程式碼相同。
TMyClass = class
public
FData:Integer;
end;
TMyClassHelper = class
public
class procedure ShowData(ASelf:TMyClass);
end;
class procedure TMyClassHelper.ShowData(ASelf:TMyClass);
begin
ShowMessage(IntToStr(ASelf.FData));
end;
procedure TForm1.Button1Click(Sender: TObject);
var
vObj : TMyClass;
begin
vObj := TMyClass.Create;
vObj.FData := 100;
TMyClassHelper.ShowData(vObj);
end;
其技術重點在於將class helper 中的函式編譯為靜態函式,並添加了一個參數,用來傳入
helped object。在呼叫端部份的程式碼則會被展開為呼叫該靜態函式,這些行為都是由
編譯器代勞,下面的程式可以證明這個論點。
procedure TForm1.Button1Click(Sender: TObject);
var
vObj : TMyClass;
vType : System.Type;
Methods : array of MemberInfo;
begin
vObj := TMyClass.Create;
vObj.HelloMyClass;
vObj.HelloMyClassHelper;
{ invoke static function of TMyClassHelper }
vType := TypeOf(TMyClassHelper);
vType.InvokeMember('HelloMyClassHelper',BindingFlags.InvokeMethod,Nil,Nil,[vObj]);
end;
當class helper 含有繼承時,其行為會稍微改變,改採Interface 來處理,由於這個課題還
牽扯到了RTL 部份,礙於篇幅,筆者就不再深入討論了。
PS:InvokeMember 是.NET Reflection 功能的一部份,其功能是由某個型別取出其方法並
呼叫,筆者將其放在下一篇:.NET Framework 中一併討論。
Next,.NET Framework 篇
本篇文章中,筆者以快速的方式引領讀者瀏覽DELPHI.NET 所新增的語言特色,不過
由於篇幅有限,實難詳述每個特色,例如record 中能定義成員函式等較少用到的功能就
被省略了,讀者們可以參考on-line help 來得到筆者所省略掉的其它細節,下次再見了!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本方案用提供Delphi7与.NET程序的协同开发, .NET程序开发服务端, Delphi7客户端。客户端只需实现界面、用户输入操作 及错误显示(提示),其他操作(包括对客户端数据集或者单条记录的校验都是发回到服务端进行的)都在服务端完成。服务端 支持部署在Web服务器(IIS, Webservice)或者独立服务器(可作为Windows程序独立运行或者Windows服务运行,TCP协议)。 "友一分销管理系统"是基于该框架实现的,详见"POS管理用户手册.doc",初始设置见"Readme.doc"。 一 .NET(C#)服务组件说明 .NET(C#)服务组件开发基于DotNetFrame4.0, 服务端集成Castle实现对AOP的支持。只要在项目中引用BuleCommon.dll程序集, 类(Class)继承于BuleCommon.BuEntity.BuEntityObj, 并且在类和方法前指定[BuleCommon.BuEntity.BuEntityAttribute()] 特性, 实现Bule_EntityRegClass : IBule_EntityRegClass注册类完成服务组件注册即可。 服务组件类框架: using BuleCommon; using BuleCommon.BuEntity; namespace BuJxcData { [BuEntity()] //使客户端能获取该服务组件(class) public class BuIOBillValidate : BuEntityObj { [BuEntity(BuEntityMethod.bemValidate)] //使客户端能获取该服务组件单记录校验方法 public virtual bool Buf_CallCalcFields(ref BuleEntityCall EntityData, ref BuRecordSet RecordSet) { } [BuEntity(BuEntityMethod.bemValidates)]//使客户端能获取该服务组件多记录校验方法 public virtual bool Buf_RefreshPriceList(ref BuleEntityCall EntityData, ref DataSet ds) { } } [BuEntity()] //使客户端能获取该服务组件(class) public class BuCustomers : BuEntityObj { [BuEntity(BuEntityMethod.bemGetName)]//使客户端能获取该服务组件根据代码获取信息方法 public BuRecordSet Buf_GetCustData(ref BuleEntityCall EntityData) { } } [BuEntity()]//使客户端能获取该服务组件(class) public class BuStockCgInBill : BuEntityObj { [BuEntity(BuEntityMethod.bemOpen)]//使客户端能获取该服务组件打开方法 public virtual DataSet Buf_OpenBillData(ref BuleEntityCall EntityData) { } [BuEntity(BuEntityMethod.bemSave)]//使客户端能获取该服务组件保存方法 override public bool Buf_SaveBillData(ref BuleEntityCall EntityData, ref DataSet ds) { } [BuEntity(BuEntityMethod.bemAudit)]//使客户端能获取该服务组件审核方法 public bool Buf_SaveCgInAuditBill(ref BuleEntityCall EntityData, ref DataSet ds) { } } } 二. Bule VCL组件说明 1.Bu_ClientObj 用于提供模块注册信息(模块名称,子系统编号,模块编号等)及访问服务器的方法(通

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值