//------------------------------------------------------------------------------------- #region << Methods >> /// <summary> /// Возвращает true, если объект заглушен, false - если зарегистрирован /// </summary> /// <param name="obj"></param> /// <param name="cox"></param> /// <param name="typeid"></param> /// <param name="objid"></param> /// <returns></returns> private static bool StubGOLObject(GlobalObject obj, SerContext cox, ushort typeid, uint objid) { if(cox.asEmptyTypes.Contains(obj.GetType()) || cox.asEmptyObjects.Contains(obj)) { #region SerObjectInfo si = new SerObjectInfo(); si.typeID = (ushort)InfraTypes.PulsarEmptyStub; si.objID = objid; si.fields = new List<SerFieldInfo>(1); SerFieldInfo fsi = new SerFieldInfo(); fsi.typeID = typeid; si.fields.Add(fsi); if(obj is GlobalObject) { fsi = new SerFieldInfo(); fsi.typeID = (ushort)PrimitiveTypes.OID; fsi.name = "oid"; fsi.value = ToBytes(((GlobalObject)obj).OID); si.fields.Add(fsi); } si.Save(cox.stream); #endregion return true; } bool noStub = cox.noStubObjects.Contains(obj); if(noStub == false && cox.noStubTypes.Count > 0) { Type t = obj.GetType(); while(t != null) if((noStub = cox.noStubTypes.Contains(t)) == true) break; else t = t.BaseType; } if(typeid == 0) typeid = cox.types.GetTypeID(obj.GetType()); if(objid == 0) objid = cox.objs.GetObjID(typeid, obj); if(noStub) { cox.stream.WriteUInt16((ushort)InfraTypes.GOLObjectRegistrator); if(Pulsar.Server.ServerParamsBase.IsServer == false && GOL.Contains(obj) == false) GOL.Add(obj); } else cox.stream.WriteUInt16((ushort)InfraTypes.GOLObjectStub); cox.stream.WriteUInt16(typeid); cox.stream.WriteUInt32(objid); cox.stream.WriteBytes(ToBytes(obj.OID)); if(noStub) { if(((IReadWriteLockObject)obj).IsLocked == false) ((IReadWriteLockObject)obj).BeginRead(); cox.stack.Push(obj); } return !noStub; }
//------------------------------------------------------------------------------------- /// <summary> /// Сериализует объект в поток. /// </summary> /// <param name="stream">Поток сериализации/</param> /// <param name="obj">Сериализуемый объект.</param> /// <param name="pars">Параметры сериализации.</param> public static void Serialize(Stream stream, object obj, PulsarSerializationParams pars) { try { if(obj == null) return; if(stream == null) throw new ArgumentNullException("stream"); if(stream.CanWrite == false) throw new Exception("Указанный поток сериализации не позволяет запись!"); SerContext cox = new SerContext(stream, pars); Type objType = obj.GetType(); if(IsPrimitive(objType) || objType == typeof(string) || objType == typeof(RefString) || obj is Array || obj is Type || obj is ISelfSerialization) obj = new PulsarPrimitiveHolder(obj); else if(cox.mode != PulsarSerializationMode.Backup && obj is GlobalObject) { if(StubGOLObject((GlobalObject)obj, cox, 0, 0)) // cox.noStubObjects.Contains(obj) == false && { stream.WriteUInt16(ushort.MaxValue); return; } } if(cox.stack.Contains(obj) == false) cox.stack.Push(obj); ushort objTypeID = 0; uint objID = 0; SerObjectInfo si = null; while(cox.stack.Count > 0) { obj = cox.stack.Pop(); objType = obj.GetType(); objTypeID = cox.types.GetTypeID(objType); objID = cox.objs.GetObjID(objTypeID, obj); if(si == null) { si = new SerObjectInfo() { fields = new List<SerFieldInfo>() }; si.fields.Add(new SerFieldInfo() { name = "$root$" }); if(obj is GlobalObject) { SerFieldInfo fsi = new SerFieldInfo(); fsi.typeID = (ushort)PrimitiveTypes.OID; fsi.name = "oid"; fsi.value = ToBytes(((GlobalObject)obj).OID); si.fields.Add(fsi); } } else si = new SerObjectInfo(); if(cox.asEmptyTypes.Contains(objType) || cox.asEmptyObjects.Contains(obj)) { #region si.typeID = (ushort)InfraTypes.PulsarEmptyStub; si.objID = objID; if(si.fields == null) si.fields = new List<SerFieldInfo>(1); SerFieldInfo fsi = new SerFieldInfo(); fsi.typeID = objTypeID; si.fields.Add(fsi); if(obj is GlobalObject) { fsi = new SerFieldInfo(); fsi.typeID = (ushort)PrimitiveTypes.OID; fsi.name = "oid"; fsi.value = ToBytes(((GlobalObject)obj).OID); si.fields.Add(fsi); } si.Save(stream); #endregion continue; } si.typeID = objTypeID; si.objID = objID; CallOnSerializing(obj, cox); if(obj is ISerializable) { #region SerializationInfo serInfo = new SerializationInfo(objType, nativeConverter); ((ISerializable)obj).GetObjectData(serInfo, new StreamingContext()); FieldWrap m_members = null; FieldWrap m_data = null; TypeSerializationWrap tw = TypeSerializationWrap.GetTypeSerializationWrap(typeof(SerializationInfo)); foreach(FieldWrap fw in tw.Fields) if(fw.Name == "m_members") m_members = fw; else if(fw.Name == "m_data") m_data = fw; if(si.fields == null) si.fields = new List<SerFieldInfo>(2); SerFieldInfo fsi = new SerFieldInfo(); fsi.typeID = (ushort)InfraTypes.StringArr; fsi.name = "m_members"; fsi.value = PackArray((Array)m_members.Get(serInfo), cox); si.fields.Add(fsi); fsi = new SerFieldInfo(); fsi.typeID = (ushort)InfraTypes.ObjectArr; fsi.name = "m_data"; fsi.value = PackArray((Array)m_data.Get(serInfo), cox); si.fields.Add(fsi); si.Save(stream); CallOnSerialized(obj, cox); #endregion continue; } string pref = ""; while(objType != typeof(object)) { //foreach(FieldInfo fi in objType.GetFields(fieldsDiscovery)) foreach(FieldWrap fw in TypeSerializationWrap.GetTypeSerializationWrap(objType).Fields) { if(fw.NoSerMode != null) if(fw.NoSerMode.Value == PulsarSerializationMode.Default || cox.mode == PulsarSerializationMode.Default || (fw.NoSerMode & cox.mode) > 0) continue; object val = fw.Get(obj); if(val == null || val is Delegate) continue; Type valType = val is Type ? typeof(Type) : val.GetType(); if(valType.IsValueType && valType == fw.Type && val.Equals(Activator.CreateInstance(valType))) continue; if(fw.ByDemandModes != null) if(fw.ByDemandModes.Value == PulsarSerializationMode.Default || cox.mode == PulsarSerializationMode.Default || (fw.ByDemandModes & cox.mode) == 0) { if(cox.opts.HasFlag(PulsarSerializationOptions.IgnoreAllByDemandSerialization) == false && cox.byDemandTypes.Contains(valType) == false) continue; } SerFieldInfo fsi = new SerFieldInfo(); fsi.typeID = cox.types.GetTypeID(valType); fsi.name = pref + fw.Name; // При добавлении, посмотреть PackArray if(fsi.typeID <= 25 || valType.IsEnum || fsi.typeID == (uint)InfraTypes.RefString) fsi.value = ToBytes(val); else if(val is ISelfSerialization) { CallOnSerializing(val, cox); fsi.value = ((ISelfSerialization)val).GetSerializedData(); CallOnSerialized(val, cox); } else if(val is Type) fsi.value = ToBytes(cox.types.GetTypeID((Type)val)); else if(val is Array) fsi.value = PackArray((Array)val, cox); else { uint id; if(cox.objs.AddAsNew(fsi.typeID, val, out id)) if(val is GlobalObject && pars != null && pars.Options.HasFlag(PulsarSerializationOptions.DeepSerialization) == false) StubGOLObject((GlobalObject)val, cox, fsi.typeID, id); else cox.stack.Push(val); fsi.value = ToBytes(id); } if(si.fields == null) si.fields = new List<SerFieldInfo>(); si.fields.Add(fsi); } objType = objType.BaseType; if(objType == null || objType == typeof(object)) break; pref += '.'; } si.Save(stream); CallOnSerialized(obj, cox); } stream.WriteUInt16(ushort.MaxValue); } catch { throw; } }
/// <summary> /// Метод десериализации объекта. /// </summary> /// <param name="stream">Поток десериализации.</param> /// <param name="root">Объект, в который будет производится десериализация.</param> /// <returns></returns> public static object Deserialize(Stream stream, object root, bool isLoad = false) { try { if(stream == null) throw new ArgumentNullException("stream"); if(stream.CanRead == false) throw new Exception("Указанный поток десериализации не позволяет чтение!"); DeserContext cox = new DeserContext(stream); ushort typeID; while((typeID = stream.ReadUInt16()) < ushort.MaxValue) { if(typeID == 0) { SerTypeInfo sti = new SerTypeInfo(); sti.Load(stream); cox.types.Process(sti); continue; } if(typeID == (ushort)InfraTypes.GOLObjectRegistrator) { #region ushort xx = stream.ReadUInt16(); Type stt = cox.types[xx]; uint stid = stream.ReadUInt32(); OID stoid = (OID)FromBytes(typeof(OID), stream.ReadBytes(16)); GlobalObject go = GOL.Get(stoid); if(go != null) { if(GOL.IsInitMode == false && isLoad == false && Pulsar.Server.ServerParamsBase.IsServer) throw new Exception("Попытка перезаписать объект на сервере!"); if(go.Equals(root) == false) cox.objs.Add(stid, new DeserObj(go)); } else { if(root != null && root is GlobalObject && ((GlobalObject)root).OID == stoid) { go = (GlobalObject)root; root = null; } else { object obj = FormatterServices.GetUninitializedObject(stt); if(obj is GlobalObject == false) throw new SerializationException(String.Format("Тип [{0}] не наследует GlobalObject!", stt.FullName)); go = (GlobalObject)obj; go.OID = stoid; } cox.objs.Add(stid, new DeserObj(go)); ////GOL.AddUninitialized(go, 0, null); GOL.Add(go); } if(isLoad == false) go.BeginWrite(); #endregion continue; } if(typeID == (ushort)InfraTypes.GOLObjectStub) { #region Type stt = cox.types[stream.ReadUInt16()]; uint stid = stream.ReadUInt32(); OID stoid = (OID)FromBytes(typeof(OID), stream.ReadBytes(16)); GlobalObject go = GOL.Locate(stt,stoid); if(go != null) { cox.objs.Add(stid, new DeserObj(go)); if(go.IsInitialized) cox.objs[stid].WaitsCount = 0; else { if(cox.lateLoad.Contains(stid) == false) cox.lateLoad.Add(stid); } ////if(GOL.IsUninitialized(stoid) == false) //// cox.objs[stid].WaitsCount = 0; ////else ////{ //// GOL.AddUninitialized(go, stid, cox); //// if(cox.lateLoad.Contains(stid) == false) //// cox.lateLoad.Add(stid); ////} } else /*if(GOL.LateInitMode == GOLLateInitModes.AllowAll || (GOL.LateInitMode == GOLLateInitModes.AllowEssences && stt.IsDefined(typeof(PulsarEssenceAttribute), true)))*/ { object obj = FormatterServices.GetUninitializedObject(stt); if(obj is GlobalObject == false) throw new SerializationException(String.Format("Тип [{0}] не наследует IGOLObject!", stt.FullName)); go = (GlobalObject)obj; go.OID = stoid; cox.objs.Add(stid, new DeserObj(go)); ////GOL.AddUninitialized(go, stid, cox); GOL.Add(go); cox.lateLoad.Add(stid); } //else // throw new SerializationException(String.Format("Заглушка объекта {{{0}}} типа [{1}] не раскрыта!", // stoid, stt.FullName)); #endregion continue; } SerObjectInfo si = new SerObjectInfo(); si.typeID = typeID; si.Load(stream); Type t = cox.types[si.typeID]; DeserObj siObjID = null; if(typeID == (ushort)InfraTypes.PulsarPrimitiveHolder) { SerFieldInfo fsi = si.index["Primitive"]; t = cox.types[fsi.typeID]; Object val = null; if(typeof(ISelfSerialization).IsAssignableFrom(t)) { val = root == null ? FormatterServices.GetUninitializedObject(t) : root; var tw = TypeSerializationWrap.GetTypeSerializationWrap(t); tw.OnDeserializing(val); ((ISelfSerialization)val).Deserialize(fsi.value); tw.OnDeserialized(val); } else val = FromBytes(t, fsi.value); return val; } if(root == null) // && cox.objs.Count == 0) && t != typeof(PulsarPrimitiveHolder) cox.objs.TryGetValue(si.objID, out siObjID); else { if(t.IsAssignableFrom(root.GetType()) == false || si.index == null || si.index.ContainsKey("$root$") == false) throw new Exception("Данные сериализации не соответствуют объекту root!"); cox.objs.Add(si.objID, siObjID = new DeserObj(root)); if(si.index.ContainsKey("oid")) ((GlobalObject)root).OID = (OID)FromBytes(typeof(OID),si.index["oid"].value); root = null; } if(t == typeof(PulsarEmptyStub)) { #region t = cox.types[si.index[""].typeID]; if(siObjID == null) cox.objs.Add(si.objID, siObjID = new DeserObj(t)); siObjID.IsEmpty = true; ConstructorInfo ci = t.GetConstructor(fieldsDiscovery, null, Type.EmptyTypes, null); if(ci != null) ci.Invoke(siObjID.Obj, null); if(si.index.ContainsKey("oid") && siObjID.Obj is GlobalObject) // if(siObjID.Obj is GlobalObject) ((GlobalObject)siObjID.Obj).OID = new OID(si.index["oid"].value); else { InterfaceMapping im = t.GetInterfaceMap(typeof(IOIDObject)); if(im.TargetMethods.Length == 0) throw new SerializationException(String.Format("Тип [{0}] не содержит свойство OID!", t.FullName)); if(t != im.TargetMethods[0].DeclaringType) t = im.TargetMethods[0].DeclaringType; PropertyInfo pi = t.GetProperty("OID", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if(pi == null) throw new SerializationException(String.Format("Тип [{0}] не содержит свойство OID!", t.FullName)); MethodInfo mi = pi.GetSetMethod(true); if(mi == null) throw new SerializationException(String.Format("Тип [{0}] не реализует set метод для свойства OID!", siObjID.Obj.GetType().FullName)); mi.Invoke(siObjID.Obj, new object[] { new OID(si.index["oid"].value) }); } #endregion siObjID.WaitsCount = 0; } if(siObjID == null) //if(typeof(GlobalObject).IsAssignableFrom(t)) // if(pars // throw new Exception("Попытка создать объект Пульсара вне GOL!"); //else cox.objs.Add(si.objID, siObjID = new DeserObj(t)); if(siObjID.WaitsCount != 0) CallOnDeserializing(siObjID.Obj); if(siObjID.WaitsCount != 0 && siObjID.Obj is ISerializable) { if(siObjID.WaitsCount == -1) siObjID.WaitsCount = 0; #region siObjID.Tag = new object[2]; SerFieldInfo fsi = si.index["m_members"]; object val = null; UnPackArray(ref val, fsi.value, typeof(string), si.objID, cox); ((object[])siObjID.Tag)[0] = val; val = null; fsi = si.index["m_data"]; UnPackArray(ref val, fsi.value, typeof(object), si.objID, cox); ((object[])siObjID.Tag)[1] = val; if(siObjID.WaitsCount != 0) continue; #endregion } if(siObjID.WaitsCount == 0) { OnFullDeser(cox, si.objID, true); continue; } string pref = ""; if(siObjID.WaitsCount == -1) siObjID.WaitsCount = 0; while(t != typeof(object)) { foreach(FieldWrap fw in TypeSerializationWrap.GetTypeSerializationWrap(t).Fields) { if(si.index == null || si.index.ContainsKey(pref + fw.Name) == false) continue; SerFieldInfo fsi = si.index[pref + fw.Name]; Type valType = cox.types[fsi.typeID]; object val = null; if(fsi.typeID <= 25 || valType.IsEnum || fsi.typeID == (uint)InfraTypes.RefString) //) && fsi.typeID != 18 && fsi.typeID != 19 ) val = FromBytes(valType, fsi.value); else if(typeof(ISelfSerialization).IsAssignableFrom(valType)) { val = FormatterServices.GetUninitializedObject(valType); TypeSerializationWrap tw = TypeSerializationWrap.GetTypeSerializationWrap(valType); tw.OnDeserializing(val); ((ISelfSerialization)val).Deserialize(fsi.value); tw.OnDeserialized(val); } else if(valType == typeof(Type)) val = cox.types[BitConverter.ToUInt16(fsi.value, 0)]; else if(valType.IsArray) UnPackArray(ref val, fsi.value, valType.GetElementType(), si.objID, cox); else { uint id = BitConverter.ToUInt32(fsi.value, 0); DeserObj dObj = null; if(cox.objs.TryGetValue(id, out dObj)) // cox.objs.ContainsKey(id) { if(dObj.WaitsCount == 0) val = dObj.Obj; else { siObjID.WaitsCount++; List<LateDeserInfo> lll; if(cox.lateSet.TryGetValue(id, out lll) == false) cox.lateSet.Add(id, lll = new List<LateDeserInfo>()); lll.Add(new LateDeserInfo(si.objID, fw)); continue; } } else { // Противоречит "глубокой" сериализации //if(typeof(GlobalObject).IsAssignableFrom(valType)) // throw new Exception("Попытка создать GlobalObject вне GOL!"); cox.objs.Add(id, new DeserObj(valType)); siObjID.WaitsCount++; List<LateDeserInfo> lll; if(cox.lateSet.TryGetValue(id, out lll) == false) cox.lateSet.Add(id, lll = new List<LateDeserInfo>()); lll.Add(new LateDeserInfo(si.objID, fw)); continue; } } fw.Set(siObjID.Obj, val); } t = t.BaseType; if(t == null || t == typeof(object)) break; pref += '.'; } if(siObjID.WaitsCount == 0) OnFullDeser(cox, si.objID, true); } if(cox.lateSet.Count > 0) //!! && GOL.LateInitMode != GOLLateInitModes.AllowAll) { #region ////List<GlobalObject> toLoad = new List<GlobalObject>(cox.lateLoad.Count); ////foreach(uint i in cox.lateLoad) //// if(cox.objs[i].Obj is GlobalObject) //// toLoad.Add((GlobalObject)cox.objs[i].Obj); //// else //// throw new Exception("Найдено неразрешимое кольцевое замыкание объектов!"); ////if(toLoad.Count == 0) //// throw new Exception("Найдено неразрешимое кольцевое замыкание объектов!"); ////GOL.LoadGlobalObjects(toLoad); if(cox.lateLoad.Count > 0) GOL.LoadGlobalObjects(cox.lateLoad.ForEach((i)=> (GlobalObject) cox.objs[i].Obj)); foreach(uint i in cox.lateLoad) { GlobalObject go = (GlobalObject) cox.objs[i].Obj; if(go.IsInitialized) OnFullDeser(cox,i,false); else throw new PulsarException("Не удалось загрузить глобальный объект [{0}] типа {1}!", go.OID, go.GetType()); } if(cox.lateSet.Count != 0) throw new Exception("Найдено неразрешимое кольцевое замыкание объектов!"); #endregion } if(cox.objs.Count == 0) return null; //if(cox.objs[1].Obj is PulsarPrimitiveHolder) // return ((PulsarPrimitiveHolder)cox.objs[1].Obj).Primitive; return cox.objs[1].Obj; } catch { //--- Debbuger Break --- // if(System.Diagnostics.Debugger.IsAttached) System.Diagnostics.Debugger.Break(); //--- Debbuger Break --- // throw; } }