/// <summary> /// Generates a collection item as bytes-array, and returns it. /// </summary> protected byte[] GenerateCollectionItemBlock(object SourceObject) { byte[] Result = null; int TypeId = -1; var DataType = (SourceObject == null ? typeof(object) : SourceObject.GetType()); byte[] Data = null; Data = GenerateNonObjectDataBlock(DataType, SourceObject); if (Data == null) { var ObjectTypeIdAndInstanceId = GenerateObjectBlock(SourceObject); if (ObjectTypeIdAndInstanceId != null) { TypeId = ObjectTypeIdAndInstanceId.Item1; Data = BitConverter.GetBytes(ObjectTypeIdAndInstanceId.Item2); // Only get the instance-id } } else { TypeId = DetectedTypes.IndexOfKey(DataType); } if (Data != null && TypeId < 0) { throw new InternalAnomaly("Type should be already registered: " + DataType.Name); } Result = BytesHandling.FusionateByteArrays(BLOCK_COL_ITM.IntoArray(), (TypeId < 0 ? new byte[0] : BitConverter.GetBytes(TypeId)), Data); return(Result); }
// --------------------------------------------------------------------------------------------------------------------------------------------------------- /// <summary> /// Generates an object-block. /// Returns type-id and object-id to be used as reference data. /// </summary> protected Tuple <int, int> GenerateObjectBlock(object Instance) { if (Instance == null) { return(null); } var InsType = Instance.GetType(); // If already traveled, just return id. var InstanceId = TravelTrace.IndexOf(Instance); if (InstanceId >= 0) { return(Tuple.Create(InsType == null ? -1 : DetectedTypes.IndexOfKey(InsType), InstanceId)); } InstanceId = TravelTrace.Count + 1; TravelTrace.Add(Instance); var ContainedFields = RegisterType(InsType); var TypeId = this.DetectedTypes.IndexOfKey(InsType); var BlocksToWrite = new List <byte[]>(); if (typeof(IEnumerable).IsAssignableFrom(InsType)) { var Items = ((IEnumerable)Instance).Cast <object>(); var ItemsCount = Items.Count(item => { if (item != null) { RegisterType(item.GetType()); // Detect new types } return(true); // include all, even empties }); this.TorrentWriter.Write(BLOCK_OBJ_COL); //- BlocksToWrite.Add(BLOCK_OBJ_COL.IntoArray()); this.TorrentWriter.Write(ItemsCount); //- BlocksToWrite.Add(BitConverter.GetBytes(ItemsCount)); foreach (var Item in Items) { var ItemBlock = GenerateCollectionItemBlock(Item); this.TorrentWriter.Write(ItemBlock); //- BlocksToWrite.Add(ItemBlock); } } else { this.TorrentWriter.Write(BLOCK_OBJ_INS); //- BlocksToWrite.Add(BLOCK_OBJ_INS.IntoArray()); this.TorrentWriter.Write(BitConverter.GetBytes(TypeId)); //- BlocksToWrite.Add(BitConverter.GetBytes(TypeId)); foreach (var Field in ContainedFields) { var Value = Field.GetValue(Instance); var DefaultTypeValue = InsType.GetDefaultValue(); if (Value == DefaultTypeValue) { continue; } var FieldBlock = GenerateObjectFieldBlock(InsType, Field, Value); this.TorrentWriter.Write(FieldBlock); //- BlocksToWrite.Add(FieldBlock); } } /*- // Now, after the object-graph tree has been traveled, proceed to write * foreach (var Block in BlocksToWrite) * this.TorrentWriter.Write(Block); */ return(Tuple.Create(DetectedTypes.IndexOfKey(Instance.GetType()), InstanceId)); }