程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> DataSnap對象傳遞

DataSnap對象傳遞

編輯:Delphi

比較簡單的方法:

1.引用DBXJSON,  DBXJSONReflect

假設有一個類:

type
  TKid = class
    FirstName: String;
    LastName: String;
    Age: Integer;
    BornDate: TDateTime;
    class function CreateAndInitialize: TKid;
  public
    function SayHello(sName:string):String;
  end;


{ TKid }

class function TKid.CreateAndInitialize: TKid;
begin
  Result := TKid.Create;
  Result.FirstName := 'Daniele';
  Result.LastName := 'Teti';
  Result.Age := 29;
  Result.BornDate := encodedate(1979,11,4);
end;

function TKid.SayHello(sName: string): String;
begin
  Result:='Hello,'+sName;
end;

 

好了,我們就可以這樣來調用(DUnit測試代碼):

=== Marshaller.Marshal(Kid) // Full qualified , Value.Get(//, Value.Get(// Reference  the = Value.Get().JsonValue , JSONKid.Get(, JSONKid.Get(, JSONKid.Get(, JSONKid.Get(, JSONKid.Get(, JSONKid.Get(, JSONKid.Get(, , )), JSONKid.Get(//== UnMarshaller.Unmarshal(Value) , , ,Kid.SayHello(;

 

序列化只對於對象本身的傳遞可以,如果傳遞的對象引用了其他的對象實例則調用含有引用對象方法時會報告錯誤。

 

下面是網絡上的一些參考資料:

 

from stackoverflow.com:

How to return a record in a DataSnap method

I wish to be able to declare a Data Snap method with the following signature

type
  TLoginInfo =record
    Username:string;
    Password:string;
    LastLogged: DateTime;end;function GetLoginInfo(const UserId: Integer): TLoginInfo;

When I try to call it it says that TLoginInfo is not well known.

Answer:

store the record into a stream and pass the stream to the DataSnap method

//on server side

function GetLoginInfo(const UserId: Integer): TStream;begin
  Result := TMemoryStream.Create;
  Result.Write( loginRec, SizeOf(TLoginInfo))
  Result.Seek(0, TSeekOrigin.soBeginning);end;

//on client side

procedure TfrmMain.getLogInto( sUser:string);var
  AStr : TStream;
  loginRec : TLoginInfo;begin//  cycleConnection;with TMethodsClient.Create( SQLConn.DBXConnection,False)dobegin

    AStr := GetLoginInfo( sUser );
    AStr.Read( loginRec, SizeOf(TLoginInfo))
    Free;end;

  FreeAndNil(AStr);end;


from http://blogs.embarcadero.com/adrian/2009/08/19/json-types-for-server-methods-in-datasnap-2010/


DataSnap 2010 (DS2010) extended the list of server method parameter types with the full suite of JSON types.

TJSONObject instance for example from a client process to a server as input or output parameter and receive a TJSONValue back as an output parameter.

DBXJSON. In the paragraphs below will be talking about creating JSON objects, writing server methods with JSON parameters and using JSON objects to marshal in and out user types.

DBXJSON unit. One can create such objects either instantiating specific types or through parsing of a byte array representing a JSON value according to specs.

TJSONObject, TJSONArrayTJSONNumberTJSONStringTJSONTrueTJSONFalseTJSONull are derived from TJSONValue and can be instantiated. TJSONPair is a type that can be only added to TJSONObject but it is not in itself a TJSONValue.

TJSONObject with a {"Hello":"World"} object:

var obj: TJSONObject; ... begin ... obj := TJSONObject.Create; obj.AddPair(TJSONPair.Create('Hello', 'World')); ...

TJSONPair has several constructors that will allow the creation of a pair less verbose. For example, in the example above is assumes that the value is actually a JSON string and creates the appropriate object.

TJSONObject class functions ParseJSONValue. They both have similar signatures, one assumes that it has to parse the entire array to create a consistent JSON object while the second expects to use only a part of it for that.

class function ParseJSONValue(const Data: TBytes; const Offset: Integer): TJSONValue; overload; static; class function ParseJSONValue(const Data: TBytes; const Offset: Integer; const Count: Integer): TJSONValue; overload; static;

Owned property that provides ownership hints when an object is destructed. The default value, true, provides the information to an eventual container that the instance can be released together with the container itself. All objects with a false property will be spared assuming that they are owned by other resources (data stores, parameters, fields). This was done to ease the construction of complex objects based on existing ones but owned by separate entities (save memory and CPU).

Clone function. This feature can be handy when server method input parameter need to be stored for longer than method execution itself.

Value property provides the Unicode representation for a TJSONString or a TJSONNumber but it has no use on other types.

function JSONPing(data: TJSONObject; var ok: TJSONValue): TJSONObject;

One cannot return an object that doesn’t own; here is where Clone method can be useful: if there is a need for any of the input parameters to be preserved outside the scope of the server method then it needs to be cloned.

Owned, but be advised that you are doing it at your own risk.

DBXConnection.

function JSONPing(data: TJSONObject; var ok: TJSONValue): TJSONObject;

constructor Create(ADBXConnection: TDBXConnection; AInstanceOwner: Boolean); overload;

DBXConnection directly, the parameter setter function SetJSONValue accepts a Boolean flag that will control the eventual destruction of its instance upon execution.

true);

DBXJSONReflect unit provides the tools needed to marshal all user types into and from JSON values.

TTypeMarshaller class is based on traversing user objects and emitting specialized events for each action; an example would be when a new object is about to be visited OnTypeStart is called. The events implementation is done through a specialization of TConverter generic class.

TJSONConverter class that can be coupled with TJSONMarshal class.

  • Field: when the field is encountered on a user type the provided converter is used instead of the default one
  • Type: when a field of that type is encountered the converter is used instead of the default one

TJSONUnMarshal that will traverse a JSON object and rebuild the user object.

record FStreet: String; FCity: String; FCode: String; FCountry: String; FDescription: TStringList; end; TPerson = class private FName: string; FHeight: integer; FAddress: TAddress; FSex: char; FRetired: boolean; FQualifications: TStringList; FChildren: array of TPerson; FNumbers: set of 1..10; public constructor Create; destructor Destroy; override; procedure AddChild(kid: TPerson); end;

FNumbers field transient and we will not marshal it in order to illustrate the warnings that are generated during the process.

var m: TJSONMarshal; unm: TJSONUnMarshal; ... begin m := TJSONMarshal.Create(TJSONConverter.Create); unm := TJSONUnMarshal.Create; ...

m) is created with the out-of-the box JSON converter. To restore the user object TJSONUnMarshal instance (unm) is part of the unit.

function(Data: TObject; Field: String): TListOfObjects var obj: TPerson; I: Integer; begin SetLength(Result, Length(TPerson(Data).FChildren)); I := Low(Result); for obj in TPerson(Data).FChildren do begin Result[I] := obj; Inc(I); end; end); m.RegisterConverter(TStringList, function(Data: TObject): TListOfStrings var i, count: integer; begin count := TStringList(Data).Count; SetLength(Result, count); for I := 0 to count - 1 do Result[i] := TStringList(Data)[i]; end); m.RegisterConverter(TPerson, 'FAddress', function(Data: TObject; Field: String): TListOfStrings var Person: TPerson; I: Integer; Count: Integer; begin Person := TPerson(Data); if Person.FAddress.FDescription <> nil then Count := Person.FAddress.FDescription.Count else Count := 0; SetLength(Result, Count + 4); Result[0] := Person.FAddress.FStreet; Result[1] := Person.FAddress.FCity; Result[2] := Person.FAddress.FCode; Result[3] := Person.FAddress.FCountry; for I := 0 to Count - 1 do Result[4+I] := Person.FAddress.FDescription[I]; end);

TPerson’s FChildren field. The list of children objects is returned as an array; these objects will be individually marshaled later.

FDescription content is appended to it.

unm instance:

procedure(Data: TObject; Field: String; Args: TListOfObjects) var obj: TObject; I: Integer; begin SetLength(TPerson(Data).FChildren, Length(Args)); I := Low(TPerson(Data).FChildren); for obj in Args do begin TPerson(Data).FChildren[I] := TPerson(obj); Inc(I); end end); unm.RegisterReverter(TStringList, function(Data: TListOfStrings): TObject var StrList: TStringList; Str: string; begin StrList := TStringList.Create; for Str in Data do StrList.Add(Str); Result := StrList; end); unm.RegisterReverter(TPerson, 'FAddress', procedure(Data: TObject; Field: String; Args: TListOfStrings) var Person: TPerson; I: Integer; begin Person := TPerson(Data); if Person.FAddress.FDescription <> nil then Person.FAddress.FDescription.Clear else if Length(Args) > 4 then Person.FAddress.FDescription := TStringList.Create; Person.FAddress.FStreet := Args[0]; Person.FAddress.FCity := Args[1]; Person.FAddress.FCode := Args[2]; Person.FAddress.FCountry := args[3]; for I := 4 to Length(Args) - 1 do Person.FAddress.FDescription.Add(Args[I]); end);

var ... person, kid: TPerson; obj: TObject; ... begin ... person := TPerson.Create; person.FName := 'John Doe'; person.FHeight := 167; person.FSex := 'M'; person.FRetired := false; person.FQualifications.Add('Delphi developer'); person.FQualifications.Add('Chess player'); person.FAddress.FStreet := '62 Peter St'; person.FAddress.FCity := 'TO'; person.FAddress.FCode := '1334566'; person.FAddress.FDescription.Add('Driving directions: exit 84 on highway 66'); person.FAddress.FDescription.Add('Entry code: 31415'); kid := TPerson.Create; kid.FName := 'Jane Doe'; person.AddChild(kid); v := m.Marshal(person); memo1.Lines.Add(v.ToString); obj := unm.Unmarshal(v); assert( obj is TPerson ); assert( TPerson(obj).FAddress.FDescription nil ); assert( TPerson(obj).FAddress.FDescription.Count > 0 ); assert( TPerson(obj).FAddress.FDescription[0] = 'Driving directions: exit 84 on highway 66', 'Description'); ... end;

memo1 component. For convenience and ease of use we formatted a little and presented it below:

HasWarnings function of the marshaller instance.

if m.HasWarnings then for I := 0 to Length(m.Warnings) - 1 do memo1.Lines.Add('Transient: ' + m.Warnings[I].FieldName); ...

  • User Objects: server side data can now be accessed by client processes
  • Business Logic: server side rules interact with client side through callbacks
  • Third party applications: Web based applications based on JavaScript can smoothly interact with server methods.

 

Custom Marshalling/UnMarshalling in Delphi 2010

 

Introduction
Some days ago, Embarcadero has presented the new version of RAD Studio, 2010.
The are many new features, but you can find in a lot places around the web, so
I won’t repeat them here.

One of the things widely requested from all Delphi programmers all over the world over the past few years, including myself, is
certainly a new and more powerful RTTI.

The new system of RTTI has finally arrived, and pave the way for a large number of applications.
One area that has benefited from the new RTTI is for sure the marshaled objects.

Marshaling is defined as follows:

“In computer science, marshalling (similar to serialization) is the process of
transforming the memory representation of an object to a data format suitable for
storage or transmission. It is typically used when data must be moved between
different parts of a computer program or from one program to another.
The opposite, or reverse, of marshalling is called unmarshalling (demarshalling) (similar to deserialization).”
–WikiPedia


In Delphi 2010 the process of serialization and deserialization is handled respectively by a Marshaller and an Unmarshaller.

The built-in format for the serialization of any Delphi object is JSON.
There are 2 main classes responsible for serializing objects into JSON, both present in the unit DBXJSONReflect:
- TJSONMarshal
- TJSONUnMarshal

Let’s say you have an object defined as follow:

type
  TKid = class
    FirstName: String;
    LastName: String;
    Age: Integer;
  end;
To serialize and deserialize an instance of TKid it requires the following steps:

var
  Mar: TJSONMarshal;  //Serializer
  UnMar: TJSONUnMarshal;  //UnSerializer
  Kid: TKid;  //The Object to serialize
  SerializedKid: TJSONObject;  //Serialized for of object
begin
  Mar := TJSONMarshal.Create(TJSONConverter.Create);
  try
    Kid := TKid.Create;
    try
      Kid.FirstName := 'Daniele';
      Kid.LastName := 'Teti';     
      Kid.Age := 29;     
      SerializedKid := Mar.Marshal(Kid) as TJSONObject;
    finally
      FreeAndNil(Kid);
    end;
  finally
    Mar.Free;
  end;
  //Output the JSON version of the Kid object
  WriteLn(SerializedKid.ToString);  
  // UnMarshalling Kid
  UnMar := TJSONUnMarshal.Create;
  try
    Kid := UnMar.UnMarshal(SerializedKid) as TKid;
    try
      //now kid is the same as before marshalling
      Assert(Kid.FirstName = 'Daniele');
      Assert(Kid.LastName = 'Teti');
      Assert(Kid.Age = 29);
    finally
      Kid.Free;
    end;
  finally
    UnMar.Free;
  end;
end;
Simple, isn’t it?
To access the JSON string that is our object, we must call the method ToString.
The JSON representation of this object SerializedKid can be saved to file,
sent to a remote server, used by a Web page from a web service, stored on a database or sent into space (!!!).
The Delphi application re-read the JSON string, you can recreate the object as it was at the time of serialization.
But anyone with a JSON parser can still read the data in our object, even non Delphi client.
These are the advantages of having used an open format and standard.

So far the simple part …
How serialize a field differently from the default?

Suppose we add the date of birth to our TKid:

type
  TKid = class
    FirstName: String;
    LastName: String;
    Age: Integer;
    BornDate: TDateTime;
  end;
Serialize a TDateTime, localized and that I have in JSON string is a float, because for Delphi TDateTime is a decimal number.
If I read the data from another program Delphi, no problem, but if I wanted to read a script in JavaScript? or. NET? or Ruby?
Then I use a format “DATA” to understand, even for these languages.
The new engine provides the serialization too.
Is needed, however, to tell the Marshaller and UnMarsheller how to represent and reconstruct a particular
object field by two statements like the following:

//marshaller
Marshaller.RegisterConverter(TKid, 'BornDate',
  function(Data: TObject; Field: string): string
  var
    ctx: TRttiContext; date : TDateTime;
  begin
    date := ctx.GetType(Data.ClassType).GetField(Field).GetValue(Data).AsType&lt;TDateTime&gt;;
    Result := FormatDateTime('yyyy-mm-dd hh:nn:ss', date);
  end);
 
//UnMarshaller
UnMarshaller.RegisterReverter(TKid, 'BornDate',
  procedure(Data: TObject; Field: string; Arg: string)
  var
    ctx: TRttiContext;
    datetime:TDateTime;
  begin
    datetime := EncodeDateTime(StrToInt(Copy(Arg, 1, 4)),
                               StrToInt(Copy(Arg, 6, 2)),
                               StrToInt(Copy(Arg, 9, 2)),
                               StrToInt(Copy(Arg, 12, 2)),
                               StrToInt(Copy(Arg, 15, 2)),
                               StrToInt(Copy(Arg, 18, 2)), 0);
    ctx.GetType(Data.ClassType).GetField(Field).SetValue(Data, datetime);
  end);
The anonymous method is called when the marshaller serializes the field ‘BornDate’ is called “Converter” while Unmarshaller anonymous method that calls when he has to reconstruct the object from the JSON string is the “Reverter”.
Thus serializing a TKid assure you that my object is readable both by Delphi from another language without loss of information.

But what happens when I have to serialize a complex type?

Suppose we extend TKid this:

type
  TTeenager = class(TKid)
    Phones: TStringList;
    constructor Create; virtual;
    destructor Destroy; virtual;
  end;
We must define a Converter and a Reverter for the TStringList class.
We can do it this way:

var
  Marshaller: TJSONMarshal;
  UnMarshaller: TJSONUnMarshal;
  Teenager: TTeenager;
  Value, JSONTeenager: TJSONObject;
begin
  Marshaller := TJSONMarshal.Create(TJSONConverter.Create);
  try
    Marshaller.RegisterConverter(TTeenager, 'BornDate',
      function(Data: TObject; Field: string): string
      var
        ctx: TRttiContext; date : TDateTime;
      begin
        date := ctx.GetType(Data.ClassType).GetField(Field).GetValue(Data).AsType&lt;TDateTime&gt;;
        Result := FormatDateTime('yyyy-mm-dd hh:nn:ss', date);
      end);
     
    Marshaller.RegisterConverter(TStringList, function(Data: TObject): TListOfStrings
                                              var
                                                i, count: integer;
                                              begin
                                                count := TStringList(Data).count;
                                                SetLength(Result, count);
                                                for i := 0 to count - 1 do
                                                  Result[i] := TStringList(Data)[i];
                                              end);  //TStringList Converter
    Teenager := TTeenager.CreateAndInitialize;
    try
      Value := Marshaller.Marshal(Teenager) as TJSONObject;
    finally
      Teenager.Free;
    end;
  finally
    Marshaller.Free;
  end;
  // UnMarshalling Teenager
  UnMarshaller := TJSONUnMarshal.Create;
  try
    UnMarshaller.RegisterReverter(TTeenager, 'BornDate',
      procedure(Data: TObject; Field: string; Arg: string)
      var
        ctx: TRttiContext;
        datetime: TDateTime;
      begin
        datetime := EncodeDateTime(StrToInt(Copy(Arg, 1, 4)),
                                   StrToInt(Copy(Arg, 6, 2)),
                                   StrToInt(Copy(Arg, 9, 2)),
                                   StrToInt(Copy(Arg, 12, 2)),
                                   StrToInt(Copy(Arg, 15, 2)),
                                   StrToInt(Copy(Arg, 18, 2)), 0);
        ctx.GetType(Data.ClassType).GetField(Field).SetValue(Data, datetime);
      end);
    UnMarshaller.RegisterReverter(TStringList, function(Data: TListOfStrings): TObject
                                               var
                                                 StrList: TStringList;
                                                 Str: string;
                                               begin
                                                 StrList := TStringList.Create;
                                                 for Str in Data do
                                                   StrList.Add(Str);
                                                 Result := StrList;
                                               end);  //TStringList Reverter
 
    Teenager := UnMarshaller.Unmarshal(Value) as TTeenager;
    try
      Assert('Daniele' = Teenager.FirstName);
      Assert('Teti' = Teenager.LastName);
      Assert(29 = Teenager.Age);
      Assert(EncodeDate(1979, 11, 4) = Teenager.BornDate);
      Assert(3 = Teenager.Phones.Count);
      Assert('NUMBER01'=Teenager.Phones[0]);
      Assert('NUMBER02'=Teenager.Phones[1]);
      Assert('NUMBER03'=Teenager.Phones[2]);
    finally
      Teenager.Free;
    end;
  finally
    UnMarshaller.Free;
  end;
end;
There are different types of Converter and Reverter.
In the the DBXJSONReflect there are 8 types of converters:

  //Convert a field in an object array
  TObjectsConverter = reference to function(Data: TObject; Field: String): TListOfObjects;
  //Convert a field in a strings array
  TStringsConverter = reference to function(Data: TObject; Field: string): TListOfStrings;
 
  //Convert a type in an objects array
  TTypeObjectsConverter = reference to function(Data: TObject): TListOfObjects;
  //Convert a type in a strings array 
  TTypeStringsConverter = reference to function(Data: TObject): TListOfStrings;
 
  //Convert a field in an object
  TObjectConverter = reference to function(Data: TObject; Field: String): TObject;
  //Convert a field in a string 
  TStringConverter = reference to function(Data: TObject; Field: string): string;
 
  //Convert specified type in an object
  TTypeObjectConverter = reference to function(Data: TObject): TObject;
  //Convert specified type in a string 
  TTypeStringConverter = reference to function(Data: TObject): string;
Each of them deals with a particular conversion object representation in the final serialization, in our case we will use them to convert to JSON.

Also in the DBXJSONReflect unit are defined many “Reverter” dealing with retrieving
the serialized version of the data and use it to reconstruct the object previously serialized.
Because they are complementary to the Converter, I will not copy them here.

As a final example, we derive from TProgrammer by TTeenager adding a list of Laptops in the properties.

Is therefore necessary to introduce a new pair of Converter / Reverter.
In this example I have defined all the converter and reverter in another unit in
order to have more readable code:

type
  TLaptop = class
    Model: String;
    Price: Currency;
    constructor Create(AModel: String; APrice: Currency);
  end;
  TLaptops = TObjectList&lt;TLaptop&gt;;
  TProgrammer = class(TTeenager)
    Laptops: TLaptops;
    constructor Create; override;
    destructor Destroy; override;
    class function CreateAndInitialize: TProgrammer;
  end;
// Implementation code…
var
  Marshaller: TJSONMarshal;
  UnMarshaller: TJSONUnMarshal;
  Programmer: TProgrammer;
  Value, JSONProgrammer: TJSONObject;
begin
  Marshaller := TJSONMarshal.Create(TJSONConverter.Create);
  try
    Marshaller.RegisterConverter(TProgrammer, 'BornDate', ISODateTimeConverter);
    Marshaller.RegisterConverter(TStringList, StringListConverter);
    Marshaller.RegisterConverter(TProgrammer, 'Laptops', LaptopListConverter);
    Programmer := TProgrammer.CreateAndInitialize;
    try
      Value := Marshaller.Marshal(Programmer) as TJSONObject;
    finally
      Programmer.Free;
    end;
 
    // UnMarshalling Programmer
    UnMarshaller := TJSONUnMarshal.Create;
    try
      UnMarshaller.RegisterReverter(TProgrammer, 'BornDate', ISODateTimeReverter);
      UnMarshaller.RegisterReverter(TStringList, StringListReverter);
      UnMarshaller.RegisterReverter(TProgrammer, 'Laptops', LaptopListReverter);
 
      Programmer := UnMarshaller.Unmarshal(Value) as TProgrammer;
      try
        Assert('Daniele' = Programmer.FirstName);
        Assert('Teti' = Programmer.LastName);
        Assert(29 = Programmer.Age);
        Assert(EncodeDate(1979, 11, 4) = Programmer.BornDate);
        Assert(3 = Programmer.Phones.Count);
        Assert('NUMBER01' = Programmer.Phones[0]);
        Assert('NUMBER02' = Programmer.Phones[1]);
        Assert('NUMBER03' = Programmer.Phones[2]);
        Assert('HP Presario C700' = Programmer.Laptops[0].Model);
        Assert(1000 = Programmer.Laptops[0].Price);
        Assert('Toshiba Satellite Pro' = Programmer.Laptops[1].Model);
        Assert(800 = Programmer.Laptops[1].Price);
        Assert('IBM Travelmate 500' = Programmer.Laptops[2].Model);
        Assert(1300 = Programmer.Laptops[2].Price);
      finally
        Programmer.Free;
      end;
    finally
      UnMarshaller.Free;
    end;
  finally
    Marshaller.Free;
  end;
end;
Unit CustomConverter.pas contains all needed Converters/Reverts as anon methods.

unit CustomConverter;
 
interface
 
uses
  DBXJSONReflect,
  MyObjects; //Needed by converter and reverter for TLaptops
 
var
  ISODateTimeConverter: TStringConverter;
  ISODateTimeReverter: TStringReverter;
 
  StringListConverter: TTypeStringsConverter;
  StringListReverter: TTypeStringsReverter;
 
  LaptopListConverter: TObjectsConverter;
  LaptopListReverter: TObjectsReverter;
 
implementation
 
uses
  SysUtils, RTTI, DateUtils, Classes;
 
initialization
 
LaptopListConverter := function(Data: TObject; Field: String): TListOfObjects
var
  Laptops: TLaptops;
  i: integer;
begin
  Laptops := TProgrammer(Data).Laptops;
  SetLength(Result, Laptops.Count);
  if Laptops.Count &gt; 0 then
    for I := 0 to Laptops.Count - 1 do
      Result[I] := Laptops[i];
end;
 
 
LaptopListReverter := procedure(Data: TObject; Field: String; Args: TListOfObjects)
var
  obj: TObject;
  Laptops: TLaptops;
  Laptop: TLaptop;
  i: integer;
begin
  Laptops := TProgrammer(Data).Laptops;
  Laptops.Clear;
  for obj in Args do
  begin
    laptop := obj as TLaptop;
    Laptops.Add(TLaptop.Create(laptop.Model, laptop.Price));
  end;
end;
 
StringListConverter := function(Data: TObject): TListOfStrings
var
  i, count: integer;
begin
  count := TStringList(Data).count;
  SetLength(Result, count);
  for i := 0 to count - 1 do
    Result[i] := TStringList(Data)[i];
end;
 
 
StringListReverter := function(Data: TListOfStrings): TObject
var
  StrList: TStringList;
  Str: string;
begin
  StrList := TStringList.Create;
  for Str in Data do
    StrList.Add(Str);
  Result := StrList;
end;
 
ISODateTimeConverter := function(Data: TObject; Field: string): string
var
  ctx: TRttiContext; date : TDateTime;
begin
  date := ctx.GetType(Data.ClassType).GetField(Field).GetValue(Data).AsType&lt;TDateTime&gt;;
  Result := FormatDateTime('yyyy-mm-dd hh:nn:ss', date);
end;
 
ISODateTimeReverter := procedure(Data: TObject; Field: string; Arg: string)
var
  ctx: TRttiContext;
  datetime :
  TDateTime;
begin
  datetime := EncodeDateTime(StrToInt(Copy(Arg, 1, 4)), StrToInt(Copy(Arg, 6, 2)), StrToInt(Copy(Arg, 9, 2)), StrToInt
      (Copy(Arg, 12, 2)), StrToInt(Copy(Arg, 15, 2)), StrToInt(Copy(Arg, 18, 2)), 0);
  ctx.GetType(Data.ClassType).GetField(Field).SetValue(Data, datetime);
end;
 
end.
Last hint…
Every serialization/unserialization process can create “warnings”.
Those warnings are collected into the “Warnings” property of the Ser/UnSer Object.

Conclusions
In this post I tried to introduce the basics of the new serialization engine in Delphi 2010.
During the next ITDevCon to be held in Italy next November 11.12, I’ll have a talk in which I will extensively talk about serialization and RTTI.
All interested smart developers are invited 

ITALIAN P.S.
Se qualche programmatore italiano volesse avere la versione in italiano di questo post può lasciare un commento e vedrò di accontentarlo 

You can find the DUnit project Source Code

 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved