德尔福 – 泛型和元帅 UnMarshal.我在这里错过了什么?第2部分 :-)

德尔福 – 泛型和元帅 UnMarshal.我在这里错过了什么?第2部分 :-),第1张

概述跟进我之前的问题:    Generics and Marshal / UnMarshal. What am I missing here? 在“第1部分”(上面的链接)中,TOndrej提供了一个很好的解决方案 – 在XE2上失败了. 在这里,我提供纠正的来源来纠正这一点 而且我认为有必要进一步扩展这个问题. 所以我想听听大家如何做到这一点: 首先 – 要在XE2和XE2更新1上运行源,请进行以 跟进我之前的问题:
   Generics and Marshal / UnMarshal. What am I missing here?

在“第1部分”(上面的链接)中,TOndrej提供了一个很好的解决方案 – 在XE2上失败了.
在这里,我提供纠正的来源来纠正这一点

而且我认为有必要进一步扩展这个问题.
所以我想听听大家如何做到这一点:

首先 – 要在XE2和XE2更新1上运行源,请进行以下更改:

Marshal.RegisterConverter(TTestObject,function (Data: TObject): String // <-- String here  begin    Result := T(Data).Marshal.ToString; // <-- ToString here  end  );

为什么?
我能看到的唯一原因必须与XE2有关,因为它有更多可用的RTTI信息.因此它将尝试并封送返回的TObject.
我在这里走在正确的轨道上吗?请随意发表评论.

更重要的是 – 该示例未实现UnMarshal方法.
如果有人可以制作一个并在此发布我会喜欢它:-)

我希望你仍然对这个问题感兴趣.

亲切的问候
比亚

解决方法 除了这个问题的答案之外,我在这里发布了一个解决方法: Generics and Marshal / UnMarshal. What am I missing here?

出于某种原因,使用TJsonobject的非默认构造函数导致XE2中的问题 – 使用默认构造函数“修复”问题.

首先,您需要将TTestobject移动到自己的单元 – 否则,在尝试解组时,RTTI将无法找到/创建您的对象.

unit uTestObject;    interface    uses      SysUtils,Classes,Contnrs,Generics.Defaults,Generics.Collections,DbxJson,DbxJsonReflect;    type      {$RTTI EXPliCIT METHODS([]) PROPERTIES([vcpublished]) FIELDS([vcPrivate])}      TTestObject=class(TObject)      private        aList:TStringList;      public        constructor Create; overload;        constructor Create(List: array of string); overload;        constructor Create(List:TStringList); overload;        destructor Destroy; overrIDe;        function Marshal:TJsonObject;        class function Unmarshal(value: TJsONObject): TTestObject;      published        property List: TStringList read aList write aList;      end;    implementation    { TTestObject }    constructor TTestObject.Create;    begin      inherited Create;      aList:=TStringList.Create;    end;    constructor TTestObject.Create(List: array of string);    var      I:Integer;    begin      Create;      for I:=low(List) to high(List) do        begin          aList.Add(List[I]);        end;    end;    constructor TTestObject.Create(List:TStringList);    begin      Create;      aList.Assign(List);    end;    destructor TTestObject.Destroy;    begin      aList.Free;      inherited;    end;    function TTestObject.Marshal:TJsonObject;    var      Mar:TJsONMarshal;    begin      Mar:=TJsONMarshal.Create();      try        Mar.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);        Result:=Mar.Marshal(Self) as TJsonObject;      finally        Mar.Free;      end;    end;    class function TTestObject.Unmarshal(value: TJsONObject): TTestObject;    var      Mar: TJsONUnMarshal;      L: TStringList;    begin      Mar := TJsONUnMarshal.Create();      try        Mar.RegisterReverter(TStringList,function(Data: TlistofStrings): TObject          var            I,Count: Integer;          begin            Count := Length(Data);            Result:=TStringList.Create;            for I := 0 to Count - 1 do              TStringList(Result).Add(string(Data[I]));          end        );        //UnMarshal will attempt to create a TTestObject from the TJsONObject data        //using RTTI lookup - for that to function,the type MUST be defined in a unit        Result:=Mar.UnMarshal(Value) as TTestObject;      finally        Mar.Free;      end;    end;    end.

另请注意,构造函数已经过载 – 这使您可以在创建过程中看到代码是有用的,而无需预先设置对象中的数据.

这是泛型类列表对象的实现

unit uTestObjectList;    interface    uses      SysUtils,DbxJsonReflect,uTestObject;    type      {$RTTI EXPliCIT METHODS([]) PROPERTIES([]) FIELDS([])}      TTestObjectList<T:TTestObject,constructor> = class(TObjectList<T>)      public        function Marshal: TJsonObject;        constructor Create;        class function Unmarshal(value: TJsONObject): TTestObjectList<T>; static;      end;    //Note: this MUST be present and initialized/finalized so that    //delphi will keep the RTTI information for the generic class available    //also,it MUST be "project global" - not "module global"    var      X:TTestObjectList<TTestObject>;    implementation    { TTestObjectList<T> }    constructor TTestObjectList<T>.Create;    begin      inherited Create;      //removed the add for test data - it corrupts unmarshaling because the data is already present at creation    end;    function TTestObjectList<T>.Marshal: TJsonObject;    var      Marshal: TJsonMarshal;    begin      Marshal := TJsONMarshal.Create;      try        Marshal.RegisterConverter(TTestObjectList<T>,function(Data: TObject): TlistofObjects          var            I: integer;          begin            SetLength(Result,TTestObjectList<T>(Data).Count);            for I:=0 to TTestObjectList<T>(Data).Count-1 do              Result[I]:=TTestObjectList<T>(Data)[I];          end        );        Result := Marshal.Marshal(Self) as TJsONObject;      finally        Marshal.Free;      end;    end;    class function TTestObjectList<T>.Unmarshal(value: TJsONObject): TTestObjectList<T>;    var      Mar: TJsONUnMarshal;      L: TStringList;    begin      Mar := TJsONUnMarshal.Create();      try        Mar.RegisterReverter(TTestObjectList<T>,function(Data: TlistofObjects): TObject          var            I,Count: Integer;          begin            Count := Length(Data);            Result:=TTestObjectList<T>.Create;            for I := 0 to Count - 1 do              TTestObjectList<T>(Result).Unmarshal(TJsONObject(Data[I]));          end        );        //UnMarshal will attempt to create a TTestObjectList<TTestObject> from the TJsONObject data        //using RTTI lookup - for that to function,the type MUST be defined in a unit,//and,because it is generic,there must be a GLOBAL VARIABLE instantiated        //so that Delphi keeps the RTTI information avaialble        Result:=Mar.UnMarshal(Value) as TTestObjectList<T>;      finally        Mar.Free;      end;    end;    initialization      //force delphi RTTI into maintaining the Generic class information in memory      x:=TTestObjectList<TTestObject>.Create;    finalization      X.Free;    end.

有几件事需要注意:
如果在运行时创建泛型类,则不保留RTTI信息,除非在内存中存在对该类的全局可访问对象引用.见:Delphi: RTTI and TObjectList<TObject>

因此,上面的单元创建了这样一个变量,并将其实例化,如链接文章中所讨论的那样.

主要过程已更新,显示两个对象的数据编组和解组:

procedure Main;    var      aTestobj,bTestObj,cTestObj : TTestObject;      aList,bList : TTestObjectList<TTestObject>;      aJsonObject,bJsonObject,cJsonObject : TJsonObject;      s: string;    begin      aTestObj := TTestObject.Create(['one','two','three','four']);      aJsonObject := aTestObj.Marshal;      s:=aJsonObject.ToString;      Writeln(s);      bJsonObject:=TJsonObject.Create;      bJsonObject.Parse(BytesOf(s),length(s));      bTestObj:=TTestObject.Unmarshal(bJsonObject) as TTestObject;      writeln(bTestObj.List.Text);      writeln('TTestObject marshaling complete.');      readln;      aList := TTestObjectList<TTestObject>.Create;      aList.Add(TTestObject.Create(['one','two']));      aList.Add(TTestObject.Create(['three']));      aJsonObject := aList.Marshal;      s:=aJsonObject.ToString;      Writeln(s);      cJsonObject:=TJsonObject.Create;      cJsonObject.Parse(BytesOf(s),length(s));      bList:=TTestObjectList<TTestObject>.Unmarshal(cJsonObject) as TTestObjectList<TTestObject>;      for cTestObj in bList do        begin          writeln(cTestObj.List.Text);        end;      writeln('TTestObjectList<TTestObject> marshaling complete.');      Readln;    end;
总结

以上是内存溢出为你收集整理的德尔福 – 泛型和元帅/ UnMarshal.我在这里错过了什么?第2部分 :-)全部内容,希望文章能够帮你解决德尔福 – 泛型和元帅/ UnMarshal.我在这里错过了什么?第2部分 :-)所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1237314.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-06
下一篇 2022-06-06

发表评论

登录后才能评论

评论列表(0条)

保存