• SuperObject TSuperRttiContext.AsType的问题及解决方法


    问题是这样的。
    在我的程序中,我用json存放用户的设置,保存到文件中。
    当我的程序版本升级时,我往用户的设置中增加了新的Fields。当我从用户的机器中读取老版本的设置时,会出现错误。我的读取与写入代码如下:

    procedure ReadFromStream<T>(Stream: TStream; var O: T);
    var
      CTX:TSuperRttiContext;
      Size:Cardinal;
      StrStream:TStringStream;
    begin
      CTX:=TSuperRttiContext.Create;
      StrStream:=TStringStream.Create;
      try
        Stream.Read(Size,SizeOf(Size));
        StrStream.CopyFrom(Stream,Size);
        O:=CTX.AsType<T>(SO(StrStream.DataString));
      finally
        CTX.Free;
        StrStream.Free;
      end;
    end;
    
    procedure WriteToStream<T>(Stream: TStream; O: T);
    var
      CTX:TSuperRttiContext;
      Size:Cardinal;
      StrStream:TStringStream;
    begin
      CTX:=TSuperRttiContext.Create;
      StrStream:=TStringStream.Create;
      try
        StrStream.WriteString(CTX.AsJson<T>(O).AsJSon);
        Size:=StrStream.Size;
        StrStream.Position:=0;
        Stream.Write(Size,SizeOf(Size));
        Stream.CopyFrom(StrStream,Size);
      finally
        CTX.Free;
        StrStream.Free;
      end;
    end;

    当我调用  ReadFromStream 去读取用户设置时, 在这行将发生错误Marshalling error :O:=CTX.AsType<T>(SO(StrStream.DataString)) .

    为了解决这个问题,我对TSuperRttiContext.FromJson方法进行了修改:

    procedure FromRecord;
      var
        f: TRttiField;
        p: Pointer;
        v: TValue;
      begin
        Result := True;
        TValue.Make(nil, TypeInfo, Value);
        for f in Context.GetType(TypeInfo).GetFields do
        begin
          if ObjectIsType(obj, stObject) and (f.FieldType <> nil) then
          begin
            p := IValueData(TValueData(Value).FHeapData).GetReferenceToRawData;
            Result := FromJson(f.FieldType.Handle, GetFieldDefault(f, obj.AsObject[GetFieldName(f)]), v);
      //modified start
            if not Result then
              TValue.Make(nil, f.FieldType.Handle, v);
            f.SetValue(p, v);
            Exit;
     // modified end
          end else
          begin
            Result := False;
            Exit;
          end;
        end;
      end;
    
    procedure FromClass;
      var
        f: TRttiField;
        v: TValue;
      begin
        case ObjectGetType(obj) of
          stObject:
            begin
              Result := True;
              if Value.Kind <> tkClass then
                Value := GetTypeData(TypeInfo).ClassType.Create;
              for f in Context.GetType(Value.AsObject.ClassType).GetFields do
                if f.FieldType <> nil then
                begin
                  Result := FromJson(f.FieldType.Handle, GetFieldDefault(f, obj.AsObject[GetFieldName(f)]), v);
                 {Modified by neugls 2011/4/5}
                 //modified start
                  if not Result then
                    TValue.Make(nil, f.FieldType.Handle, v);
                 
                  f.SetValue(Value.AsObject, v);
                  Exit;
                 //modified end
                end;
            end;
          stNull:
            begin
              Value := nil;
              Result := True;
            end
        else
          // error
          Value := nil;
          Result := False;
        end;
      end;

     

    总结:问题的根源在于,如果ISuperObject 实例中没有与TypeInfo对应的field话,就会失败,而我的修改就是绕过了这个!

  • 相关阅读:
    短信验证倒计时60s
    jquery select省市区三级联动
    C# 遍历文本框
    html formData 数据 提交和 .netMVC接收
    jq遍历table 下的 td 添加类
    jq 替换DOM layeui 不刷新
    jq 获取表单所有数据
    js 二级联动
    MVC 下载文件
    MVC 上传文件
  • 原文地址:https://www.cnblogs.com/neugls/p/2005919.html
Copyright © 2020-2023  润新知