Regression: RTTI information is missing in IList<T>

Issue #320 wontfix
Ondrej Pokorny created an issue

The “develop” branch of Spring4D misses RTTI information in IList<T> (and possibly in other interfaces as well). The “master” branch includes RTTI information in IList<T>.

As a result “develop” Spring4D interfaces cannot be serialized/deserialized with RTTI any more.

Please add serializable versions of Spring4D interfaces that include RTTI. E.g. ISerializableList<T> and/or similar.

Test code:

procedure ListIListMethods;
var
  MyContext: TRttiContext;
  MyRttiType: TRttiType;
  MyMethod: TRttiMethod;
begin
  MyContext := TRttiContext.Create;
  MyRttiType := MyContext.GetType(TypeInfo(IList<Integer>));
  for MyMethod in MyRttiType.GetMethods do
    Writeln(MyMethod.Name);
end;

Comments (4)

  1. Stefan Glienke repo owner

    This is as designed as RTTI adds quite some overhead - it does not require RTTI to serialize and deserialize collections.

    You can use the non generic interfaces IEnumerable and ICollection to serialize and deserialize almost every collection.

  2. Ondrej Pokorny reporter

    You fail to see that I do not have access to IEnumerable and ICollection unless I create a dependency on Spring4D (add Spring4D units to uses). RTTI allows me to decouple the serialization engine from Spring4D.

    If you create dedicated interfaces that include RTTI information you won’t have any overhead in base interfaces:

    IList<T> - no RTTI, no overhead
    ISerializableList<T> - with RTTI, with overhead

    Only people who want or need the RTTI will use the ISerializableList<T> interfaces. So no overhead for the others.

  3. Ondrej Pokorny reporter

    Here is a proof-of-concept code for ISerializableList<T>:

      {$M+}
      ISerializableEnumerator<T> = interface
        ['{FF1CF9C5-AA17-4903-B5E2-BB954F65D46B}']
        function GetCurrent: T;
        function MoveNext: Boolean;
      end;
      TSerializableEnumerator<T> = class(TInterfacedObject, ISerializableEnumerator<T>)
      var
        fEnumerator: Spring.Collections.IEnumerator<T>;
      public
        function GetCurrent: T;
        function MoveNext: Boolean;
        constructor Create(const aEnumerator: Spring.Collections.IEnumerator<T>);
      end;
    
      {$M+}
      ISerializableList<T> = interface(Spring.Collections.IList<T>)
      ['{2D89E86C-69F9-444A-ADAE-81A1B5BC1C9F}']
        function Add(const item: T): Integer;
        procedure Clear;
        function GetEnumerator: ISerializableEnumerator<T>;
      end;
      TSerializableFoldedList<T> = class(TFoldedList<T>, ISerializableList<T>)
      public
        function GetEnumerator: ISerializableEnumerator<T>;
      end;
    
      [xml('myserobject')]
      TSerObject = record
        [xmlcollection(''), xml('mylist')]
        List: ISerializableList<IItem>;
      end;
    
      TCollectionsHelper = class helper for TCollections
      public
        class function CreateSerializableList<T>: ISerializableList<T>; overload; static;
      end;
    
    { TCollectionsHelper }
    
    class function TCollectionsHelper.CreateSerializableList<T>: ISerializableList<T>;
    begin
      Result := TSerializableFoldedList<T>.Create(TypeInfo(T), nil);
    end;
    
    { TSerializableFoldedList<T> }
    
    function TSerializableFoldedList<T>.GetEnumerator: ISerializableEnumerator<T>;
    begin
      Result := TSerializableEnumerator<T>.Create(inherited GetEnumerator);
    end;
    
    { TSerializableEnumerator<T> }
    
    constructor TSerializableEnumerator<T>.Create(
      const aEnumerator: Spring.Collections.IEnumerator<T>);
    begin
      inherited Create;
    
      fEnumerator := aEnumerator;
    end;
    
    function TSerializableEnumerator<T>.GetCurrent: T;
    begin
      Result := fEnumerator.Current;
    end;
    
    function TSerializableEnumerator<T>.MoveNext: Boolean;
    begin
      Result := fEnumerator.MoveNext;
    end;
    
  4. Log in to comment