DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: tkzcol
今日帖子: 4
在线用户: 1
导航: 论坛 -> DELPHI技术 斑竹:liumazi,sephil  
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2023/8/9 16:54:14
标题:
delphi自带的TJsonSerializer其实很好用了 浏览:2916
加入我的收藏
楼主: unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  System.JSON.Serializers, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
type
  TRecA = record
    stringValue: string;
    datetimeValue: TDateTime;
    integerValue: Integer;
    doubleValue: Double;
  end;

  TRecB = record
    stringValue: string;
    datetimeValue: TDateTime;
    integerValue: Integer;
    doubleValue: Double;
  end;

  TRecAB = record
    A: TRecA;
    B: TRecB;
  end;
begin
  var AB: TRecAB;
  AB.A.stringValue := 'hello world';
  AB.A.datetimeValue := Now;
  AB.A.integerValue := 123;
  AB.A.doubleValue := 3.1415926;

  AB.B.stringValue := 'HELLO WORLD';
  AB.B.datetimeValue := Now;
  AB.B.integerValue := 666;
  AB.B.doubleValue := 3.1415927;

  var Arr: TArray<TRecAB>;

  SetLength(Arr, 1);

  Arr[0] := AB;

  var s := TJsonSerializer.Create;
  Memo1.Text := s.Serialize<TArray<TRecAB>>(Arr);

  var d := TJsonSerializer.Create;
  var EmptyArray: TArray<Integer> := d.Deserialize<TArray<Integer>>('[]');
  Caption := Length(EmptyArray).ToString;
end;

end.
----------------------------------------------
学无止境
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2023/8/9 16:55:34
1楼: 记不清什么时候有的,个人感觉还是很好用的.
----------------------------------------------
学无止境
作者:
男 hnxxcxg (咏南中间件) ★☆☆☆☆ -
盒子活跃会员
2023/8/9 18:00:07
2楼: 10.2 tokyo开始有的。
----------------------------------------------
中间件QQ群: 92449782 博客: http://www.cnblogs.com/hnxxcxg/
作者:
男 ksrsoft (cb168) ★☆☆☆☆ -
普通会员
2023/8/9 19:43:38
3楼: TJsonSerializer确实很好用  序列化 反序列化
----------------------------------------------
-
作者:
男 hi100 (hi100) ▲▲▲▲△ -
普通会员
2023/8/9 21:42:05
4楼: 能不能把 Memo1.Text里的内容,再反序列化到数组呢?
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2023/8/9 21:43:22
4楼: 能搞 TObjectList 吗?
----------------------------------------------
-
作者:
男 ghs_79 (ghs) ★☆☆☆☆ -
盒子活跃会员
2023/8/10 9:03:10
5楼: 1、Memo1.Text当然可以么序列化。
  var d := TJsonSerializer.Create;
  var EmptyArray := d.Deserialize<TArray<TRecAB>>(Memo1.Text);
2、TObjectList<T>,泛型可以序列化。
----------------------------------------------
Delphi爱好者。
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2023/8/10 12:59:05
6楼: 泛型可以也行。我试试。
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2023/8/10 13:21:25
7楼: 谢谢楼主。

我以前用的是 TJson.JsonToObject 和 TJson.ObjectToJsonString 感觉有 BUG;

这个 TJsonSerializer 针对 TObjectList 简单测试了一下,没有问题。
----------------------------------------------
-
作者:
男 jingzu (123456) ★☆☆☆☆ -
盒子活跃会员
2023/8/10 14:47:21
8楼: 这个很好用啊,但怎么把 Memo1.Text 再放到AB(Arr[0])中?
----------------------------------------------
永远是DELPHI初学者。
作者:
男 ghs_79 (ghs) ★☆☆☆☆ -
盒子活跃会员
2023/8/10 17:17:25
9楼: 用TObjectList<T>序列化格式的差异。
  ====objList直接序列化======  
{"FOwnsObjects":true,"FListHelper":[{"Fid":1000,"FName":"测试中"}],"FComparer":{}}
  ====objList.ToArray()再序列化======  
[{"Fid":1000,"FName":"测试中"}]
----------------------------------------------
Delphi爱好者。
作者:
男 hi100 (hi100) ▲▲▲▲△ -
普通会员
2023/8/10 17:35:43
10楼: 感谢 ghs_79,测试可行。
----------------------------------------------
-
作者:
男 chencong5025 (Nicosoft) ▲▲▲△△ -
普通会员
2023/8/11 20:53:19
11楼: 缺陷很明显 无法解析动态数据。

比如
type
  MyRecord=record
    name:string;
    value:Tobject;
  end;
  Test=class
    p1:string;
  end;
procedure TForm3.Button1Click(Sender: TObject);
begin
    var json:='{"name":"你好","Value":{"p1":"value1"}}';
    var ser:=TJsonSerializer.Create;
    var outdata:=ser.Deserialize<Myrecord>(json);

    memo1.Lines.Add(outdata.name);

    if outdata.value=nil then
      memo1.Lines.Add('null');
    memo1.Lines.Add(Test(outdata.value).p1 );
end;

当然肯定有人会说 你要定义一个结构之类的。事实是 动态结构经常用,其他语言支持 Delphi不行
----------------------------------------------
-
作者:
男 powerpcer (大强) ★☆☆☆☆ -
禁用账号
2023/8/11 21:05:10
12楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
呆湾傻冒
作者:
男 zhyhero (zhyhero) ★☆☆☆☆ -
盒子活跃会员
2023/8/12 9:10:42
13楼: 为何不直接用value:TJsonobject
----------------------------------------------
z@S7
作者:
男 chencong5025 (Nicosoft) ▲▲▲△△ -
普通会员
2023/8/12 13:10:46
14楼: @powerpcer
最烦你这种人。不行就是不行   Delphi定位是RAD  C#定位也是RAD  人家行 D不行 这有什么可叽歪的。
----------------------------------------------
-
作者:
男 powerpcer (大强) ★☆☆☆☆ -
禁用账号
2023/8/12 14:47:42
15楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
呆湾傻冒
作者:
男 ghs_79 (ghs) ★☆☆☆☆ -
盒子活跃会员
2023/8/12 16:14:03
16楼: 类不行,可以用record来代替
  Test = record
    p1: string;
  end;

  MyRecord<T> = record
    name: string;
    value: T; //类不行,可以是记录
  end;
----------------------------------------------
Delphi爱好者。
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2023/8/13 11:58:43
17楼: type
  MyRecord=record
    name:string;
    value:Tobject;  //换为 Test应该能解决问题。
  end;
  Test=class
    p1:string;
  end;

如果还有
  TestA = class
    p1: string;
  end;
  
TestB = class
   p1: string;
  end;

反序列化的时候,应该用哪个? 所以指定反序列化的需要指定具体类型。
----------------------------------------------
学无止境
作者:
男 janker (janker) ★☆☆☆☆ -
盒子活跃会员
2023/8/13 14:26:28
18楼: 但是好像只对直接的“类型”进行操作,不对属性进行操作。

XI惯了只操作public和published的属性,这样好控制。

还有如何隐藏一些不要转换的字段,没搞明白。一些第三方的直接通过Attribute来控制隐藏成员和控制格式,指定大小写等。
----------------------------------------------
-
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2023/8/13 16:04:53
19楼: to: 楼上
var s := TJsonSerializer.Create;
//TJsonDefaultContractResolver 默认是Fields,这里替换为public
s.ContractResolver := TJsonDefaultContractResolver.Create(TJsonMemberSerialization.&Public);

TJsonMemberSerialization = (Fields, &Public, &In);

另外,In不清楚什么意思,help文档里对这块没有描述,望清楚的大神给解下惑。
----------------------------------------------
学无止境
作者:
男 janker (janker) ★☆☆☆☆ -
盒子活跃会员
2023/8/13 17:33:09
20楼: @jjwwang 谢谢
用public,可以操作属性了,但是,好奇怪:

  TMyChild = class
  private
    FAge: Integer;
    FIsMoreCard: Boolean;
    FTitle: string;
    procedure SetTitle(const Value: string);
    procedure SetAge(const Value: Integer);
    procedure SetIsMoreCard(const Value: Boolean);
  public
    procedure Assign(Source: TObject);

    property Title: string read FTitle write SetTitle;
    property Age: Integer read FAge write SetAge;
    property IsMoreCard: Boolean read FIsMoreCard write SetIsMoreCard;
  end;

  //{$M+}
  TMyTestObj = class(TPersistent)
  private

    FNum: Integer;
    FMSet: TMySet;
    FStr: string;
    FEnum: TMyEnum;
    FStartDate: TDateTime;
    FBirthDate: TDate;
    FChild: TMyChild;
    FStrList: TStrings;
    FItems: TObjectList<TMyChild>;
    FOthers: TObjectDictionary<string, TMyChild>;
    procedure SetEnum(const Value: TMyEnum);
    procedure SetMSet(const Value: TMySet);
    procedure SetNum(const Value: Integer);
    procedure SetStr(const Value: string);
    procedure SetStartDate(const Value: TDateTime);
    procedure SetBirthDate(const Value: TDate);
    procedure SetChild(const Value: TMyChild);
    procedure SetItems(const Value: TObjectList<TMyChild>);
    procedure SetOthers(const Value: TObjectDictionary<string, TMyChild>);
    procedure SetStrList(const Value: TStrings);
  public
    constructor Create;
    destructor Destroy; override;

    var TestStr: string;

    property Items: TObjectList<TMyChild> read FItems write SetItems;
    property StrList: TStrings read FStrList write SetStrList;
    property Others: TObjectDictionary<string, TMyChild> read FOthers write SetOthers;

  published
    property Str: string read FStr write SetStr;
    property Num: Integer read FNum write SetNum;
    property Enum: TMyEnum read FEnum write SetEnum;
    property StartDate: TDateTime read FStartDate write SetStartDate;
    property BirthDate: TDate read FBirthDate write SetBirthDate;
    property MSet: TMySet read FMSet write SetMSet;
    property Child: TMyChild read FChild write SetChild;
  end;
  //{$M-}

测试:

  aSer := TJsonSerializer.Create;
  aSer.ContractResolver := TJsonDefaultContractResolver.Create(TJsonMemberSerialization.Public);
  aSer.Formatting := TJsonFormatting.Indented; //格式化

结果:

========Serialize=======
{
    "TestStr": "Test Test String",
    "Items": {
        "OwnsObjects": true,
        "Capacity": 0,
        "Count": 0,
        "List": [],
        "Comparer": {}
    },
    "StrList": {
        "Duplicates": 0,
        "Sorted": false,
        "CaseSensitive": false,
        "OwnsObjects": false,
        "Updating": false,
        "Capacity": 4,
        "CommaText": "1234567890,222222222,333333333",
        "Count": 3,
        "DefaultEncoding": {
          "CodePage": 936,
          "EncodingName": "936   (ANSI/OEM - 简体中文 GBK)",
          "MIMEName": "gbk",
          "IsSingleByte": false
        },
        "Delimiter": ",",
        "DelimitedText": "1234567890,222222222,333333333",
        "Encoding": {
          "CodePage": 936,
          "EncodingName": "936   (ANSI/OEM - 简体中文 GBK)",
          "MIMEName": "gbk",
          "IsSingleByte": false
        },
        "LineBreak": "\r\n",
        "QuoteChar": "\"",
        "NameValueSeparator": "=",
        "StrictDelimiter": false,
        "Text": "1234567890\r\n222222222\r\n333333333\r\n",
        "StringsAdapter": null,
        "WriteBOM": true,
        "TrailingLineBreak": true,
        "UseLocale": true,
        "Options": 14
    },
    "Others": {
        "Capacity": 0,
        "Count": 0,
        "GrowThreshold": 0,
        "Collisions": 0,
        "Keys": {
          "Count": 0
        },
        "Values": {
          "Count": 0
        },
        "Comparer": {}
    },
    "Str": "中国人",
    "Num": 123,
    "Enum": 0,
    "StartDate": "2023-08-13T17:31:27.566+08:00",
    "BirthDate": "2003-01-30T00:00:00.000+08:00",
    "MSet": 5,
    "Child": {
        "Title": "Child",
        "Age": 22,
        "IsMoreCard": true
    }
}

对于TStringList,输出了不需要的。。。
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2023/8/13 17:41:32
21楼: 哪些是不需要的?
----------------------------------------------
-
作者:
男 janker (janker) ★☆☆☆☆ -
盒子活跃会员
2023/8/13 17:55:04
22楼: @pcplayer

    "Items": {
        "OwnsObjects": true,
        "Capacity": 0,
        "Count": 0,
        "List": [],
        "Comparer": {}
    },
    "StrList": {
        "Duplicates": 0,
        "Sorted": false,
        "CaseSensitive": false,
        "OwnsObjects": false,
        "Updating": false,
        "Capacity": 4,
        "CommaText": "1234567890,222222222,333333333",
        "Count": 3,
        "DefaultEncoding": {
          "CodePage": 936,
          "EncodingName": "936   (ANSI/OEM - 简体中文 GBK)",
          "MIMEName": "gbk",
          "IsSingleByte": false
        },
        "Delimiter": ",",
        "DelimitedText": "1234567890,222222222,333333333",
        "Encoding": {
          "CodePage": 936,
          "EncodingName": "936   (ANSI/OEM - 简体中文 GBK)",
          "MIMEName": "gbk",
          "IsSingleByte": false
        },

这里的信息,好多是类本身的属性,不是用户数据。
Delphi内部用应当没问题,和其它语言交流就不行了
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2023/8/13 18:09:58
23楼: 这些当然是有用的。没有这些信息,如果要把这个 JSON 恢复为一个 TStringList 对象,怎么恢复?

至于和其它语言交流,每个语言里面的对象都不一样,怎么交流?如果你仅仅需要用户数据,你直接用 StringList.Lines 就好了,它本身就是字符串。

没有格式这些信息,仅仅有用户数据,其它语言拿到,也没法使用。比如 "CodePage": 936, 这个如果没有,不管哪个语言,它也没法知道你的用户数据,也就是你的字符串,应该是什么编码,不知道编码,它怎么使用?

这个其实和【其它语言】无关。即便是 Delphi 这个语言,如果有另外一种 StringList 对象,它的代码实现方式和 TStringList 不一样,也没法使用这个 JSON 的。

说白了,JSON 本身是一种数据格式,但它并没有跨语言交换数据的标准,没有标准,当然就得自己处理。

就好比当年所有语言都狂推的 XML,它也是个数据格式。但是,基于  XML 数据格式的 SOAP 通讯协议,是有跨语言的标准的。所以如果两个语言都遵循 SOAP 协议,是可以互相调用的  -- 也就是一个语言输出的 XML 数据,另外一个语言能够使用。

但如果不是 SOAP 协议,而是自己用 XML 封装的数据,那其它语言,甚至相同语言的其它的代码,也不一定能解析理由这个数据。
----------------------------------------------
-
作者:
男 janker (janker) ★☆☆☆☆ -
盒子活跃会员
2023/8/13 18:12:51
23楼: 用XSuperObject测试:TObjectList<T>可以,不会输出额外的信息。
用TJsonSerializer测试:TObjectList<T>还是会输出额外信息。

如果不想要额外信息,不要用TStringList, TDictionary, TObjectDictionary等容器。
----------------------------------------------
-
作者:
男 janker (janker) ★☆☆☆☆ -
盒子活跃会员
2023/8/13 18:16:44
24楼: @pcplayer
就是遇到了和Python,php,java等的交流情况,DELPHI做客户端,交流就是用json数据。
所以还得处理隐藏成员,改名,大小写等要求。
----------------------------------------------
-
作者:
男 powerpcer (大强) ★☆☆☆☆ -
禁用账号
2023/8/13 18:43:09
25楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
呆湾傻冒
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2023/8/13 20:15:00
26楼: 24 楼,这个和语言无关。和该语言的具体的库有关,甚至和使用该语言写某个具体的程序的人有关 -- 因为 JSON 只是数据的一种格式,但这个格式下的数据该是什么样子,并没有标准。所以,不可能随便一个格式的 JSON 数据,能够反序列化为某个具体类型的对象。比如,反序列化为 TStringList。反过来,假设 Python 里面有一个类叫做 TPyStringList,也不是随便一个 JSON 就能反序列化创建这个 TPyStringList 类型的对象的。

如果不处理具体的对象,仅仅是处理 JSON 格式封装的数据,那就用 Delphi 的 TJSONObject, TJSonPair 这样的单纯处理 JSON 数据的类。

所以,你的问题,要让 TStringList 输出的 JSON 去和其它程序(什么语言并不重要,即便那个程序是 Delphi 写的)沟通,本身就是个伪问题。本来就不应该这样做,也不可能这样做。这个和 Delphi 没关系。即便是一个 Python 写的程序,要和另外一个 Python 写的程序沟通,如果没有标准的通讯协议,两边处理 JSON 使用的类库不同,使用的类类型不同,也是没法直接把这边的对象输出的 JSON 到那边直接反序列化为另外一个对象的。都是肉,总不能这边的牛肉到那边变成猪肉吧?
----------------------------------------------
-
作者:
男 chencong5025 (Nicosoft) ▲▲▲△△ -
普通会员
2023/8/13 21:43:23
27楼: @powerpcer
你有意思么?抠字眼很好玩?是个人都知道我说的啥意思。

那Delphi也不算语言啊  Object-Pascal才算。真有意思。
----------------------------------------------
-
作者:
男 chencong5025 (Nicosoft) ▲▲▲△△ -
普通会员
2023/8/13 21:44:47
28楼: @jjwwang
如果制定了Test了的话 不就是固定了结构了
如果value 是个变化的 就不可以了。

C# 那边有个 动态类型了  现在可以包万物。包括序列化
----------------------------------------------
-
作者:
男 powerpcer (大强) ★☆☆☆☆ -
禁用账号
2023/8/13 22:06:53
29楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
呆湾傻冒
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2023/8/13 22:18:54
30楼: TXXX = class
  strValue: string;
  arrObj: TArray<TMyObj>;
end;
对接其它语言过来的Json或提供json,上面方式基本上差不多了。在复杂的情况下,个人觉得要根据实际情况生成具体的json.
----------------------------------------------
学无止境
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2023/8/13 22:19:53
31楼:
  TObjectValue = class
  private
    FValue: string;
  public
    constructor Create(AValue: string);
    property Value: string read FValue write FValue;
  end;

  TTestObject = class
  private
    FObjectList: TObjectList<TObjectValue>;
  public
    constructor Create;
    destructor Destroy; override;
    property ObjectList: TObjectList<TObjectValue> read FObjectList;
  end;


{ TTestObject }

constructor TTestObject.Create;
begin
  inherited Create;
  FObjectList := TObjectList<TObjectValue>.Create;
  FObjectList.Add(TObjectValue.Create('ABC'));
  FObjectList.Add(TObjectValue.Create('A123'));
  FObjectList.Add(TObjectValue.Create('B333'));
end;

destructor TTestObject.Destroy;
begin
  FObjectList.Free;
  inherited;
end;

{ TObjectValue }

constructor TObjectValue.Create(AValue: string);
begin
  inherited Create;
  FValue := AValue;
end;

像这种情况下,应该什么什么样的JSON呢?
----------------------------------------------
学无止境
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2023/8/13 22:22:19
32楼: {
    "ObjectList": {
        "List": [
          {
          "Value": "ABC"
          },
          {
          "Value": "A123"
          },
          {
          "Value": "B333"
          }
        ]
    }
}



{
       [
          {
          "Value": "ABC"
          },
          {
          "Value": "A123"
          },
          {
          "Value": "B333"
          }
        ]
}
在不同的情况下,个人觉得这两种都是正确的.
----------------------------------------------
学无止境
作者:
男 janker (janker) ★☆☆☆☆ -
盒子活跃会员
2023/8/13 23:07:03
29楼: @pcplayer
我的意思不是凭空根据JSON就生成Delphi的Object,Delphi的Record。
一个具体的Delphi类型(Object,Record等)肯定一一对应一个JSON结构。
11楼说的那个动态类型,太厉害了,我想不通Delphi里怎么生成。

我是吐槽TJsonSerializer不方便使用,看了源码,也不知道怎么下手包装。
没有类似第三方的XSuperObject使用方便,不用包装就可以用于提交数据(比如微信,支付宝的API调用)。

比如使用XSuperObject:
1、TList<T>,TObjectList<T>,TArray<T>不会输出额外信息,这是希望的。TList<T>和TArray<T>都可以作为容器字段类型。
2、可以使用Alias这个Attribute可以方便改变字段名称,这个挺需要的。有些服务端提供的JSON结构,命名像天书,Delphi里还是XI惯简单明了的字段名称。
3、隐藏或忽略某些字段。这个也是挺需要的。比如ID字段,不希望JSON结构数据里传送这个ID,序列化的时候就可以通过Disabled或Ignore的Attribute来指明。

XSuperObject源码简单明了,XSuperObject添加一些定制的Attribute比较简单。
TJsonSerializer源码看得头晕,无从下手。

如果没有用到序列化部分,还可以用JsonDataObject这个JSON库。
只是JsonDataObject对序列化的支持太简单了,实际不够使用。有个开源的包装,开源项目DelphiMVCFrameWork,提供了JsonDataObject的序列化包装,但是感觉不如XSuperObject简单明了。
----------------------------------------------
-
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2023/8/13 23:27:43
33楼: to: 楼上
[JsonIgnoreAttribute] //打上这个就不序列化了, delphi已内置定义了
property JsonIgnoreAttribute: string read FJsonIgnoreAttribute;
----------------------------------------------
学无止境
作者:
男 janker (janker) ★☆☆☆☆ -
盒子活跃会员
2023/8/13 23:35:42
34楼: @jjwwang
我看了半天,没找到JsonIgnoreAttribute在哪里声明
----------------------------------------------
-
作者:
男 janker (janker) ★☆☆☆☆ -
盒子活跃会员
2023/8/13 23:38:51
35楼: @jjwwang
找到了,在单元开头,呵呵...
----------------------------------------------
-
作者:
男 janker (janker) ★☆☆☆☆ -
盒子活跃会员
2023/8/14 0:04:11
36楼: 再测试了下:
TJsonSerializer 用TArray<T>序列化后不会输出容器额外信息,
TList<T>和TObjectList<T>会额外输出容器信息

@jjwwang:是不是有地方可以关了这个额外输出的信息?
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2023/8/14 1:12:39
37楼: 29 楼说的那些,其实是表明你不知道你的需求和 Delphi 的那个 TJsonSerializer 的设计目标,根本不是一回事。相当于你想吃猪肉,去吐槽一家牛肉店。

TJsonSerializer 能够解决我想要的一个需求:把一堆的对象,也就是 TObjectList 里面的一堆对象,序列化为字符串,然后再反序列化为 TObjectList;它要解决这个,不带任何的类信息或者对象信息,很难搞。

你要的是仅仅输出数据。但是,仅仅输出数据,其实并不是你要的。你还没明白你要什么。需求分析,正确地提出自己的需求和问题,才是问题的核心。

对于 JSON 来说,它就是用字符串来表达的一种数据格式,类似 XML。在遵循它的基本格式的情况下,同样的数据,不同的人,设计的具体格式可能不同。这也就是我说的,你输出的 JSON 格式,不一定能给另外一个程序用,不管这个程序是什么语言写的。除非大家对于格式有个约定,有一个相同的格式标准。

所以,问题并不是什么只要数据,不要类的信息之类的问题。前面我也说了,输出的字符串列表,如果输出信息里面不包含编码信息,另外一边拿到这个 JSON 也无法处理。但是,包含编码信息的话,JSON 又没有一个标准说这个编码信息必须放在哪里,因为没有标准,如果另外一个接收信息的程序它处理数据的标准不一样,也没法处理。

同样是字符串,比如 HTML 就有标准,必须在头部有 <meta CharSet="UTF8"/> 这样的信息。既然它是标准,那么不管什么语言,处理 HTML 的代码,就都会处理。如果没有这个标准,一个语言处理这个信息时认为它应该在头部(<head>),另外一个语言处理这个信息时认为它应该在 <Body> 部分,那么 A 程序输出的 HTML 给到 B 程序也没法正确处理。

因此,你要的不是仅仅输出数据,而是输出的数据的 JSON 格式,符合你目前面对的需求环境,比如,假设你目前需要对接某个其它的系统,不管这个系统是用什么语言开发的,你需要搞明白的是那个系统需要的数据结构,JSON 的格式。

所以,这里没什么好吐槽的。Delphi 能够做的其实就 2 种:

A. Delphi 自己的类输出的 JSON 数据再转化为 Delphi 自己的类。这种情况,Delphi 自己搞定,无需考虑别人有什么格式或者标准。这个就是 TStringList 的情况;

B. 如果有业界标准,Delphi 如果决定支持这个业界标准,那它会有库,输出符合业界标准的 JSON;

至于你现在想要的那种数据格式,如果没有业界标准,那肯定 Delphi 官方的代码不会去支持,你想要就只能自己写代码实现了。
----------------------------------------------
-
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2023/8/14 8:58:16
38楼: to: 是不是有地方可以关了这个额外输出的信息?

我没找到取巧的办法,都是用TArray<T>
----------------------------------------------
学无止境
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2023/8/14 9:03:47
39楼:   TTestObject = class
  private
    FObjectList: TObjectList<TObjectValue>;
    function GetObjectArray: TArray<TObjectValue>;
  public
    constructor Create;
    destructor Destroy; override;
    [JsonIgnoreAttribute]
    property ObjectList: TObjectList<TObjectValue> read FObjectList;
    property ObjectArray: TArray<TObjectValue> read GetObjectArray;
  end;

{
    "ObjectArray": [
        {
          "Value": "ABC"
        },
        {
          "Value": "A123"
        },
        {
          "Value": "B333"
        }
    ]
}

这是目前我能想到的
----------------------------------------------
学无止境
作者:
男 janker (janker) ★☆☆☆☆ -
盒子活跃会员
2023/8/14 13:02:00
40楼: @jjwwang
固定用TArray<T>也行,只是没有TList<T>方便。

内置的Attribute:
JsonConverterAttribute:这个是干嘛的,难道是就是干11楼说的动态解析用的?
JsonIgnoreAttribute:隐藏
JsonNameAttribute:改名
JsonInAttribute:这个不知道干嘛
JsonObjectHandlingAttribute:这个也不知道干嘛
JsonObjectOwnership:这个是拥有关系
JsonSerializeAttribute:这个是指定序列化器?

没有文档,没有Demo....
----------------------------------------------
-
作者:
男 chencong5025 (Nicosoft) ▲▲▲△△ -
普通会员
2023/8/14 13:31:19
41楼: @powerpcer

有个成语叫固步自封 可以研究下。

就你还在着 跑车货车  人家C#是什么车  你来说说
----------------------------------------------
-
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2023/8/14 14:46:07
42楼: 完善版贴子在这里
https://bbs.2ccc.com/topic.asp?topicid=681707
----------------------------------------------
学无止境
作者:
男 powerpcer (大强) ★☆☆☆☆ -
禁用账号
2023/8/14 14:56:41
43楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
呆湾傻冒
作者:
男 isxuzhu (e.Wong) ★☆☆☆☆ -
盒子活跃会员
2023/8/14 16:58:27
44楼: 收藏,学xi了
----------------------------------------------
你我,都可以是个造梦者!欢迎加入脚本引擎PaxCompiler交流群303904495http://www.cnblogs.com/fireboxsoft有需要错别字检测软件的朋友可以在我博客上的地址下载使用,备注“2ccc”的朋友可以免费获取超级黄金VVVVVVVVVVIP授权
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2023/8/15 10:56:19
45楼: 收藏了
----------------------------------------------
-
作者:
男 chencong5025 (Nicosoft) ▲▲▲△△ -
普通会员
2023/8/15 21:41:42
46楼: @powerpcer
怎么  骂着 骂着  又变繁体了?
看来不是大陆人
----------------------------------------------
-
作者:
男 powerpcer (大强) ★☆☆☆☆ -
禁用账号
2023/8/16 6:23:54
47楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
呆湾傻冒
作者:
男 siaosa (siaosa) ★☆☆☆☆ -
盒子活跃会员
2023/8/16 8:19:58
48楼: Delphi/Pascal跌出TIOBE的编程语言排行榜前20名是有原因的。
----------------------------------------------
-
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2023/8/16 9:57:02
49楼: 11 楼:
不知道你所谓的“解析动态数据”是不是这个意思?
此帖子包含附件:
PNG 图像
大小:39.3K
----------------------------------------------
武汉天气不好
作者:
男 powerpcer (大强) ★☆☆☆☆ -
禁用账号
2023/8/16 10:03:05
49楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
呆湾傻冒
作者:
男 tuesdays (Tuesday) ▲▲▲▲△ -
普通会员
2023/8/16 11:55:28
50楼: EMB 自李维离开后, 就已经改公司方针了, 
EMB 的终身目标就是卖盘, 期望微软或者amd, 哪怕是sun来收购. 天天朌月月等,
----------------------------------------------
delphi界写python最强, python界写delphi最强. 写自己的代码, 让别人去运行.
作者:
男 powerpcer (大强) ★☆☆☆☆ -
禁用账号
2023/8/16 16:33:06
51楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
呆湾傻冒
作者:
男 chencong5025 (Nicosoft) ▲▲▲△△ -
普通会员
2023/8/17 14:32:25
52楼: @dbyoung

就是比如 Json

{"name":"hello","Value":{"p1":[]}}

Value可以是字符串 可能是数组 可能是对象  
但是我们不知道。
如何解析到一个实体
----------------------------------------------
-
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2023/8/17 17:11:55
53楼: to: chencong5025 (Nicosoft)
这个肯定还有上下文吧,不然在 js 里都不知道怎么写。

//没问题
console.log(obj.name) -> hello
//没问题
console.log(obj.value) ->会输出些内容

//??写什么,至少要判断个原型,看是不是个array才能具体写。
console.log(obj.value?. what?)
----------------------------------------------
学无止境
作者:
男 tuesdays (Tuesday) ▲▲▲▲△ -
普通会员
2023/8/17 17:56:44
54楼: @jjwwang 
js, php都不分类型,  json在这些语言中都数组. 
访问 obj['name']  php则是 $obj['name']
----------------------------------------------
delphi界写python最强, python界写delphi最强. 写自己的代码, 让别人去运行.
作者:
男 powerpcer (大强) ★☆☆☆☆ -
禁用账号
2023/8/17 18:07:52
55楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
呆湾傻冒
作者:
男 chencong5025 (Nicosoft) ▲▲▲△△ -
普通会员
2023/8/17 20:18:20
56楼: @jjwwang

本来我也没在意 但是当我看到C#的代码 我就真不淡定了。

        public static TypedDataRaw DeserialiseJsonToRawTypedData<DomainType>(string json, string messageKeySelector = "message")
        {
          var convertor = new ExpandoObjectConverter();
          var jsonDeserialised = JsonConvert.DeserializeObject<IDictionary<string, object>>(json, convertor);


后续代码我就不复制了  太长。看着一段就能看出大概了。

他是讲Json解析成了 一个键值字典。

然后值用的时候是 

var types = jsonDeserialised["types"] as IDictionary<string, object>;

直接这样转换即可 因为值是Object类型。
----------------------------------------------
-
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2023/8/17 21:19:49
57楼: to: chencong5025
我不太懂C#,刚刚在网上查了一下关于 Expando 关键字,找了一篇文章,
https://www.zhangjunbk.com/article/7030
关于C# 4.0 中的 Expando 对象,有这么一段话:

动态对象方案 动态对象的目标并不是要取代高质量的静态类型。在可预见的将来,静态类型仍然会保留在软件开发的基础中。通过静态类型化,您可以在编译时可靠地查找类型错误并生成代码;而且正因为如此,生成的代码无需在运行时进行检查,运行速度更快。此外,略过编译步骤的需求使得开发人员和架构师必须在设计软件和定义交互层的公共接口时格外小心。

使用 ExpandoObject 类 Expando 对象不是为 .NET Framework 发明的,事实上,它们比 .NET 还早出现几年。我第一次听到有人用这个术语来描述 JScript 对象是在 20 世纪 90 年代中期。Expando 是一种可扩充的对象,其结构完全是在运行时定义的。在 .NET Framework 4 中,您像使用传统的托管对象一样使用 Expando,不同之处在于其结构不在任何程序集外读取,而完全是动态构建的。

----------

C#/.net底层如何操作的不清楚,但在使用时,我觉得还是有类似装箱/拆箱类似的事情,或许有些类似Variant。
----------------------------------------------
学无止境
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2023/8/17 21:23:17
58楼: 不管如何,
var types = jsonDeserialised["types"] as IDictionary<string, object>;

从types中取出object后,在使用时,因为不知道object是数组或对象或字符串等,如果 不进行类型判定,使用是有可能产生异常的---这也只是我个人猜测。
----------------------------------------------
学无止境
作者:
男 zhyhero (zhyhero) ★☆☆☆☆ -
盒子活跃会员
2023/8/17 21:53:50
59楼: 动态的变体?

TDocVariant custom variant type
----------------------------------------------
z@S7
作者:
男 powerpcer (大强) ★☆☆☆☆ -
禁用账号
2023/8/17 22:00:38
59楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
呆湾傻冒
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2023/8/17 22:21:09
60楼: {
  "name": "some project",
  "people": [
    { "name": "some person", "owns": [] },
    { "name": "some person", "owns": [] },
    { "name": "some person", "owns": [] }
  ],
  "cats": [
    { "name": "some cat" },
    { "name': "some cat"  },
    { "name": "some cat" },
    { "name": "some cat" },
    { "name": "some cat" },
    { "name": "some cat" }
  ]
}
----反序列化
some project
3
some person
0
----------------------------------------------
学无止境
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2023/8/17 22:21:51
61楼:   TPeople = class
  private
    FName: string;
    FOwns: TArray<string>;
  published
    property name: string read FName write FName;
    property owns: TArray<string> read FOwns;
  end;

  TCat = class
  private
    FName: string;
  published
    property name: string read FName write FName;
  end;

  TTestObject = class
  private
    FName: string;
    FPeople: TArray<TPeople>;
    FCats: TArray<TCat>;
  published
    property name: string read FName write FName;
    property people: TArray<TPeople> read FPeople;
    property cats: TArray<TCat> read FCats;
  end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  var O := TTestObject.Create;
  if ObjectLoadJson(O, Memo1.Text) then
    Memo1.Lines.Add('ok');

  Memo1.Lines.Add(O.name);
  Memo1.Lines.Add(Length(O.people).ToString);
  Memo1.Lines.Add(O.people[0].Name);
  Memo1.Lines.Add(Length(O.cats).ToString);
end;
----------------------------------------------
学无止境
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2023/8/17 22:25:13
62楼: ObjectLoadJson是 mormot2  mormot.core.json单元中的一个函数
----------------------------------------------
学无止境
作者:
男 powerpcer (大强) ★☆☆☆☆ -
禁用账号
2023/8/17 22:51:19
63楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
呆湾傻冒
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2023/8/18 7:57:03
64楼: to: powerpcer (大强)

[ 123, 'abc', [ 123, 'abc' ], { name: 'nick' } ]

你用c#实体化再输出,不要用类似Variant变体的方式。
----------------------------------------------
学无止境
作者:
男 powerpcer (大强) ★☆☆☆☆ -
禁用账号
2023/8/18 8:54:37
65楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
呆湾傻冒
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2023/8/18 9:21:24
66楼: to: powerpcer (大强)
这里没人说什么什么语言或框架多强多厉害,作这种口舌之争没有意义。
如果你见过其它语言中一些“神奇”的事情,可以在这里说出来大家一起探讨底层机制是什么,在Delphi,c#,java, py等中是否能实现,或如何变通实现,最终能或不能都可以接受。
----------------------------------------------
学无止境
作者:
男 powerpcer (大强) ★☆☆☆☆ -
禁用账号
2023/8/18 10:04:08
67楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
呆湾傻冒
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2023/8/18 10:22:29
68楼: 我没再问你什么吧,哈,不过正好想回复下 chencong5025,
顺便感谢下zhyhero (zhyhero),让我看了那篇文章,也研究了一个特殊JSON的处理.

to: chencong5025

procedure TForm1.FormCreate(Sender: TObject);
begin
  var a := _Json('[ 123, "abc", [ 456, "hellow world" ], { "name": "nick" } ]');
  caption := Format('%s_%s_%s', [a._(0), a._(2)._(1), a._(3).name]);
end;
这可能说明不了什么,但多少有些类似。
----------------------------------------------
学无止境
作者:
男 powerpcer (大强) ★☆☆☆☆ -
禁用账号
2023/8/21 9:10:12
69楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
呆湾傻冒
作者:
男 chencong5025 (Nicosoft) ▲▲▲△△ -
普通会员
2023/8/21 12:44:56
70楼: @jjwwang

其实 动态结构还是可以将就。毕竟情况比较少。但是多层次的结构就不好弄了。

就和我之前说的json  如果value 是个3层或者5层或者8层的结构。

那么我们定义实体类型的时候 实在是不好定义了。

而C#的那个代码就可以完美解决。

这个讨论本就无关优劣,只是说我看到C#有这个东西 很神奇。(当时曾经尝试翻译 才发现的)
----------------------------------------------
-
作者:
男 powerpcer (大强) ★☆☆☆☆ -
禁用账号
2023/8/21 12:53:17
71楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
呆湾傻冒
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行120.1172毫秒 RSS