全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:1899
推到 Plurk!
推到 Facebook!

对象的序列化 -- 把一个 Object 变成字符串,再从字符串变回 Object

 
pcplayer99
尊榮會員


發表:142
回覆:740
積分:591
註冊:2003-01-21

發送簡訊給我
#1 引用回覆 回覆 發表時間:2015-04-13 18:45:14 IP:50.116.xxx.xxx 訂閱
在 DELPHI 传统的 RTTI 基础上,可以把一个对象(必须是 TComponent)的 published 的属性序列化为字符串。这样做,必须满足:
1. 是 TComponent 或子类;
2. 必须注册这个类型。在 initialization 里面:RegisterClass(TPeer);
代码如下:
//这个方法,将一个 TComponent 序列化为字符串。实际上只序列化了它的 published 的属性。
function ComponentToStringProc(Component: TComponent): string;
var
BinStream:TMemoryStream;
StrStream: TStringStream;
s: string;
begin
BinStream := TMemoryStream.Create;
try
StrStream := TStringStream.Create(s);
try
BinStream.WriteComponent(Component);
BinStream.Seek(0, soFromBeginning);
ObjectBinaryToText(BinStream, StrStream);
StrStream.Seek(0, soFromBeginning);
Result:= StrStream.DataString;
finally
StrStream.Free;
end;
finally
BinStream.Free
end;
end;
//这个方法,将字符串,反序列化为一个 TComponent. 具体序列化为哪个子类,就需要做类型转换,As TMyComponent。
//但必须要使系统知道这个子类,否则执行异常。要让系统知道子类型,就要在初始化 initialization 里面,用 RegisterClass(TPeer); 来注册。
function StringToComponentProc(Value: string): TComponent;
var
StrStream:TStringStream;
BinStream: TMemoryStream;
begin
StrStream := TStringStream.Create(Value);
try
BinStream := TMemoryStream.Create;
try
ObjectTextToBinary(StrStream, BinStream);
BinStream.Seek(0, soFromBeginning);
Result:= BinStream.ReadComponent(nil);
finally
BinStream.Free;
end;
finally
StrStream.Free;
end;
end;
调用上述两个函数的代码:
Component 转换为字符串:
procedure TForm1.Button3Click(Sender: TObject);
var
Peer: TPeer;
S: string;
begin
Peer := TPeer.Create(nil);
try
Peer.PeerName := 'James';
Peer.PeerIP := '192.168.2.5';
Peer.PeerPort := 3256;
Peer.Name := 'Peer' Peer.PeerName;
S := ComponentToStringProc(Peer);
Memo1.Lines.Add(S);
finally
Peer.Free;
end;
end;
字符串恢复为 Component:
procedure TForm1.Button4Click(Sender: TObject);
var
APeer: TPeer;
begin
APeer := StringToComponentProc(Memo1.Lines.Text) as TPeer;
Memo1.Lines.Clear;
try
Memo1.Lines.Add(APeer.Name);
Memo1.Lines.Add(Apeer.PeerName);
Memo1.Lines.Add(APeer.PeerIP);
Memo1.Lines.Add(IntToStr(APeer.PeerPort));
finally
APeer.Free;
end;
end;

------------------------------------------
如果要把对象转换为 JSON 字符串,再转换回来,采用 REST.JSON 单元的 TJSON 的方法。这里可以对任何对象的 public 的属性进行序列化。也不需要注册对象类型。
对象转换为 JSON 字符串:
procedure TForm1.Button1Click(Sender: TObject);
var
APeer: TPeerA;
begin
APeer := TPeerA.Create; //(nil);
APeer.PeerName := 'James';
APeer.PeerIP := '192.168.9.0';
APeer.PeerPort := 234;
try
Memo1.Lines.Text := TJson.ObjectToJsonString(APeer); //REST.JSON 单元的 TJson 的方法。它序列化一个 Class 的 public 属性。不需要是 TComponent 也不需要是 published.
finally
APeer.Free;
end;
end;
JSON字符串转换为对象:
procedure TForm1.Button2Click(Sender: TObject);
var
S: string;
APeer: TPeerA;
begin
S := Memo1.Lines.Text;
APeer := TJson.JsonToObject(S);
try
//Memo1.Lines.Add(APeer.Name);
Memo1.Lines.Add(Apeer.PeerName);
Memo1.Lines.Add(APeer.PeerIP);
Memo1.Lines.Add(IntToStr(APeer.PeerPort));
finally
APeer.Free;
end;
end;
GrandRURU
站務副站長


發表:234
回覆:1654
積分:1752
註冊:2005-06-21

發送簡訊給我
#2 引用回覆 回覆 發表時間:2015-05-08 09:18:45 IP:59.120.xxx.xxx 訂閱
謝謝分享!
herbert2
尊榮會員


發表:58
回覆:632
積分:878
註冊:2004-04-16

發送簡訊給我
#3 引用回覆 回覆 發表時間:2015-05-13 00:49:56 IP:202.39.xxx.xxx 訂閱
謝謝分享!只是有點好奇,這樣做的目地為何?
十幾年前從 CBC3 開始,便有利用 TScreen->Tag 貯存 Application MainForm 之 Tstrings Address point,
再於 ChildForm 轉回 TStrings 以取得整個 MDI Form 的公用控制變數,
也用 TStrings 將字串格式化為控制參數,以做為各種指令的座標、變數等;
但不知將 Property 也這樣傳遞之妙用何在?不知可否灌頂一下?
pcplayer99
尊榮會員


發表:142
回覆:740
積分:591
註冊:2003-01-21

發送簡訊給我
#4 引用回覆 回覆 發表時間:2015-06-19 01:17:14 IP:120.236.xxx.xxx 訂閱
很多用处。

比如,你有很多 parameters 在你的程式里面,如何组织?最简单的办法是用一个 Object,把这些 Parameters 当作这个 Object 的 Porperty。这样一来,你的 code 里面,任何需要这个 Parameter 的地方,你可以写: MySQLConnectionStr := MyObj.MyConnectionParameter; 类似这种写法。当你需要把一组很多个 Parameter 保存到 File 里面,下次程式启动时再用,一个办法是保存为 INI,一条一条地去写 MyIni.WriteString(); MyIni.WriteInteger(); 有多少条 Parameter 就写多少条。另一个办法就是直接把这个 Object 变成 string 写入 File,下次程式启动再从这个 File 加载到 Object 里面。

更进一步,如果你想通过网络来传递这个 Object 到网络另外一边的程式..............
GrandRURU
站務副站長


發表:234
回覆:1654
積分:1752
註冊:2005-06-21

發送簡訊給我
#5 引用回覆 回覆 發表時間:2015-06-22 09:30:37 IP:59.120.xxx.xxx 訂閱
受教了,謝謝你的分享!
===================引 用 pcplayer99 文 章===================
很多用处。

比如,你有很多 parameters 在你的程式里面,如何组织?最简单的办法是用一个 Object,把这些 Parameters 当作这个 Object 的 Porperty。这样一来,你的 code 里面,任何需要这个 Parameter 的地方,你可以写: MySQLConnectionStr := MyObj.MyConnectionParameter; 类似这种写法。当你需要把一组很多个 Parameter 保存到 File 里面,下次程式启动时再用,一个办法是保存为 INI,一条一条地去写 MyIni.WriteString(); MyIni.WriteInteger(); 有多少条 Parameter 就写多少条。另一个办法就是直接把这个 Object 变成 string 写入 File,下次程式启动再从这个 File 加载到 Object 里面。

更进一步,如果你想通过网络来传递这个 Object 到网络另外一边的程式..............
pcplayer99
尊榮會員


發表:142
回覆:740
積分:591
註冊:2003-01-21

發送簡訊給我
#6 引用回覆 回覆 發表時間:2015-08-09 11:50:16 IP:183.15.xxx.xxx 訂閱
上面的 code 里面,把一个 Object 变成 JSON String 的代码,在 XE7 底下测试是没有问题的。

这两天在 XE8 底下,发现时不时会出现 Exception,尤其是在 Android 底下。上网搜索了一下,发现很多人提这个 Exception,确定是 XE8 的 Bug.
系統時間:2017-11-20 15:44:01
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!