/// <summary> /// Reads an *implementation specific* bundled .NET object, including (as options) type-metadata, identity/re-use, etc. /// </summary> public static object ReadNetObject(object value, ProtoReader source, int key, Type type, NetObjectOptions options) { SubItemToken token = ProtoReader.StartSubItem(source); int fieldNumber; int newObjectKey = -1, newTypeKey = -1, tmp; while ((fieldNumber = source.ReadFieldHeader()) > 0) { switch (fieldNumber) { case FieldExistingObjectKey: tmp = source.ReadInt32(); value = source.NetCache.GetKeyedObject(tmp); break; case FieldNewObjectKey: newObjectKey = source.ReadInt32(); break; case FieldExistingTypeKey: tmp = source.ReadInt32(); type = (Type)source.NetCache.GetKeyedObject(tmp); key = source.GetTypeKey(ref type); break; case FieldNewTypeKey: newTypeKey = source.ReadInt32(); break; case FieldTypeName: string typeName = source.ReadString(); type = source.DeserializeType(typeName); if (type == null) { throw new ProtoException("Unable to resolve type: " + typeName + " (you can use the TypeModel.DynamicTypeFormatting event to provide a custom mapping)"); } key = source.GetTypeKey(ref type); if (key < 0) { throw new InvalidOperationException("Dynamic type is not a contract-type: " + type.Name); } break; case FieldObject: bool isString = type == typeof(string); bool lateSet = value == null && isString; if (value == null && !lateSet) { try { value = ((options & NetObjectOptions.UseConstructor) == 0) ? BclHelpers.GetUninitializedObject(type) : Activator.CreateInstance(type); } catch (Exception ex) { throw new ProtoException("Unable to create type " + (type == null ? "<null>" : type.FullName) + ": " + ex.Message, ex); } } if (newObjectKey >= 0 && !lateSet) { source.NetCache.SetKeyedObject(newObjectKey, value); if (newTypeKey >= 0) { source.NetCache.SetKeyedObject(newTypeKey, type); } } object oldValue = value; if (isString) { value = source.ReadString(); } else { value = ProtoReader.ReadTypedObject(oldValue, key, source, type); } if (newObjectKey >= 0 && lateSet) { source.NetCache.SetKeyedObject(newObjectKey, value); if (newTypeKey >= 0) { source.NetCache.SetKeyedObject(newTypeKey, type); } } if (newObjectKey >= 0 && !lateSet && !ReferenceEquals(oldValue, value)) { throw new ProtoException("A reference-tracked object changed reference during deserialization"); } if (newObjectKey < 0 && newTypeKey >= 0) { // have a new type, but not a new object source.NetCache.SetKeyedObject(newTypeKey, type); } break; default: source.SkipField(); break; } } if (newObjectKey >= 0 && (options & NetObjectOptions.AsReference) == 0) { throw new ProtoException("Object key in input stream, but reference-tracking was not expected"); } ProtoReader.EndSubItem(token, source); return(value); }
/// <summary> /// Reads an *implementation specific* bundled .NET object, including (as options) type-metadata, identity/re-use, etc. /// </summary> public static object ReadNetObject(object value, ProtoReader source, int key, Type type, NetObjectOptions options) { SubItemToken token = ProtoReader.StartSubItem(source); int fieldNumber; int newObjectKey = -1, newTypeKey = -1, tmp; while ((fieldNumber = source.ReadFieldHeader()) > 0) { switch (fieldNumber) { case FieldExistingObjectKey: tmp = source.ReadInt32(); value = source.NetCache.GetKeyedObject(tmp); break; case FieldNewObjectKey: newObjectKey = source.ReadInt32(); break; case FieldExistingTypeKey: tmp = source.ReadInt32(); type = (Type)source.NetCache.GetKeyedObject(tmp); key = source.GetTypeKey(ref type); break; case FieldNewTypeKey: newTypeKey = source.ReadInt32(); break; case FieldTypeName: type = source.DeserializeType(source.ReadString()); key = source.GetTypeKey(ref type); break; case FieldObject: bool isString = type == typeof(string); bool lateSet = value == null && isString; if (value == null && !lateSet) { value = ((options & NetObjectOptions.UseConstructor) == 0) ? BclHelpers.GetUninitializedObject(type) : Activator.CreateInstance(type); } if (newObjectKey >= 0 && !lateSet) { source.NetCache.SetKeyedObject(newObjectKey, value); if (newTypeKey >= 0) { source.NetCache.SetKeyedObject(newTypeKey, type); } } object oldValue = value; if (isString) { value = source.ReadString(); } else { value = ProtoReader.ReadTypedObject(oldValue, key, source, type); } if (newObjectKey >= 0 && lateSet) { source.NetCache.SetKeyedObject(newObjectKey, value); if (newTypeKey >= 0) { source.NetCache.SetKeyedObject(newTypeKey, type); } } if (!lateSet && !ReferenceEquals(oldValue, value)) { throw new ProtoException("A reference-tracked object changed reference during deserialization"); } break; default: source.SkipField(); break; } } ProtoReader.EndSubItem(token, source); return(value); }