I started with the code from Mark:
Type TObjectStream Method ReadObject:Object() 'read type name Local name$=_stream.ReadLine() 'find type Local id:TTypeId=TTypeId.ForName( name ) 'create new object! Local obj:Object=id.NewObject() 'restore it's fields... For Local fld:TField=EachIn id.EnumFields() 'ignore non-serializable fields If Not fld.MetaData( "serializable" ) Continue 'get type of field Local fldType:TTypeId=fld.TypeId() 'is field an object or int/float etc? If fldType.ExtendsType( ObjectTypeId ) 'field is an object - recurse fld.Set obj,ReadObject() Else 'field must be int/float etc...a 'leaf' fld.Set obj,_stream.ReadLine() EndIf Next Return obj End Method Method WriteObject( obj:Object ) 'what type of object is it? Local id:TTypeId=TTypeId.ForObject( obj ) 'write it's type name, eg: "TMyType" _stream.WriteLine id.Name() 'scan it's fields... For Local fld:TField=EachIn id.EnumFields() 'ignore non-serializable fields If Not fld.MetaData( "serializable" ) Continue 'get type of field Local fldType:TTypeId=fld.TypeId() 'is field an object or int/float etc? If fldType.ExtendsType( ObjectTypeId ) 'field is an object - recurse WriteObject fld.Get( obj ) Else 'field must be int/float etc...a 'leaf' _stream.WriteLine fld.Get( obj ).ToString() EndIf Next End Method Field _stream:TStream 'underlying stream End Type