-//\r
-// System.Runtime.Serialization.ObjectManager.cs\r
-//\r
-// Author: Lluis Sanchez Gual (lluis@ideary.com)\r
-//\r
-// (C) 2003 Lluis Sanchez Gual\r
-//\r
-\r
-//\r
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)\r
-//\r
-// Permission is hereby granted, free of charge, to any person obtaining\r
-// a copy of this software and associated documentation files (the\r
-// "Software"), to deal in the Software without restriction, including\r
-// without limitation the rights to use, copy, modify, merge, publish,\r
-// distribute, sublicense, and/or sell copies of the Software, and to\r
-// permit persons to whom the Software is furnished to do so, subject to\r
-// the following conditions:\r
-// \r
-// The above copyright notice and this permission notice shall be\r
-// included in all copies or substantial portions of the Software.\r
-// \r
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
-//\r
-\r
-using System;\r
-using System.Collections;\r
-using System.Reflection;\r
-\r
-namespace System.Runtime.Serialization\r
-{\r
-#if NET_2_0\r
- [System.Runtime.InteropServices.ComVisibleAttribute (true)]\r
-#endif\r
- public class ObjectManager\r
- {\r
- // All objects are chained in the same order as they have been registered\r
- ObjectRecord _objectRecordChain = null;\r
- ObjectRecord _lastObjectRecord = null;\r
-\r
- ArrayList _deserializedRecords = new ArrayList();\r
-#if NET_2_0\r
- ArrayList _onDeserializedCallbackRecords = new ArrayList();\r
-#endif\r
- Hashtable _objectRecords = new Hashtable();\r
- bool _finalFixup = false;\r
-\r
- ISurrogateSelector _selector;\r
- StreamingContext _context;\r
- int _registeredObjectsCount = 0;\r
-\r
- public ObjectManager(ISurrogateSelector selector, StreamingContext context)\r
- {\r
- _selector = selector;\r
- _context = context;\r
- }\r
-\r
- public virtual void DoFixups()\r
- {\r
- _finalFixup = true;\r
-\r
- try\r
- {\r
- if (_registeredObjectsCount < _objectRecords.Count)\r
- throw new SerializationException ("There are some fixups that refer to objects that have not been registered");\r
-\r
-\r
- ObjectRecord last = _lastObjectRecord;\r
- bool firstCicle = true;\r
-\r
- // Solve al pending fixups of all objects\r
-\r
- ObjectRecord record = _objectRecordChain;\r
- while (record != null)\r
- {\r
- bool ready = !(record.IsUnsolvedObjectReference && firstCicle);\r
- if (ready) ready = record.DoFixups (true, this, true);\r
- if (ready) ready = record.LoadData(this, _selector, _context);\r
-\r
- ObjectRecord next;\r
-\r
- if (ready)\r
- {\r
- if (record.OriginalObject is IDeserializationCallback)\r
- _deserializedRecords.Add (record);\r
-\r
-#if NET_2_0\r
- SerializationCallbacks sc = SerializationCallbacks\r
- .GetSerializationCallbacks (record.OriginalObject.GetType ());\r
- if (sc.HasDeserializedCallbacks)\r
- _onDeserializedCallbackRecords.Add (record);\r
-#endif\r
- next = record.Next;\r
- }\r
- else\r
- {\r
- // There must be an unresolved IObjectReference instance.\r
- // Chain the record at the end so it is solved later\r
-\r
- if ((record.ObjectInstance is IObjectReference) && !firstCicle)\r
- {\r
- if (record.Status == ObjectRecordStatus.ReferenceSolvingDelayed)\r
- throw new SerializationException ("The object with ID " + record.ObjectID + " could not be resolved");\r
- else\r
- record.Status = ObjectRecordStatus.ReferenceSolvingDelayed;\r
- }\r
-\r
- if (record != _lastObjectRecord) {\r
- next = record.Next;\r
- record.Next = null;\r
- _lastObjectRecord.Next = record;\r
- _lastObjectRecord = record;\r
- }\r
- else\r
- next = record;\r
- }\r
-\r
- if (record == last) firstCicle = false;\r
- record = next;\r
- }\r
- }\r
- finally\r
- {\r
- _finalFixup = false;\r
- }\r
- }\r
-\r
- internal ObjectRecord GetObjectRecord (long objectID)\r
- {\r
- ObjectRecord rec = (ObjectRecord)_objectRecords[objectID];\r
- if (rec == null)\r
- {\r
- if (_finalFixup) throw new SerializationException ("The object with Id " + objectID + " has not been registered");\r
- rec = new ObjectRecord();\r
- rec.ObjectID = objectID;\r
- _objectRecords[objectID] = rec;\r
- }\r
- if (!rec.IsRegistered && _finalFixup) throw new SerializationException ("The object with Id " + objectID + " has not been registered");\r
- return rec;\r
- }\r
-\r
- public virtual object GetObject (long objectID)\r
- {\r
- if (objectID <= 0) throw new ArgumentOutOfRangeException("objectID","The objectID parameter is less than or equal to zero");\r
- ObjectRecord rec = (ObjectRecord)_objectRecords[objectID];\r
- if (rec == null || !rec.IsRegistered) return null;\r
- else return rec.ObjectInstance;\r
- }\r
-\r
- public virtual void RaiseDeserializationEvent ()\r
- {\r
-#if NET_2_0\r
- for (int i = _onDeserializedCallbackRecords.Count-1; i >= 0; i--)\r
- {\r
- ObjectRecord record = (ObjectRecord) _onDeserializedCallbackRecords [i];\r
- RaiseOnDeserializedEvent (record.OriginalObject);\r
- }\r
-#endif\r
- for (int i = _deserializedRecords.Count-1; i >= 0; i--)\r
- {\r
- ObjectRecord record = (ObjectRecord) _deserializedRecords [i];\r
- IDeserializationCallback obj = record.OriginalObject as IDeserializationCallback;\r
- if (obj != null) obj.OnDeserialization (this);\r
- }\r
-\r
- }\r
-\r
-#if NET_2_0\r
- public void RaiseOnDeserializingEvent (object obj)\r
- {\r
- SerializationCallbacks sc = SerializationCallbacks\r
- .GetSerializationCallbacks (obj.GetType ());\r
- sc.RaiseOnDeserializing (obj, _context);\r
- }\r
-\r
- void RaiseOnDeserializedEvent (object obj)\r
- {\r
- SerializationCallbacks sc = SerializationCallbacks\r
- .GetSerializationCallbacks (obj.GetType ());\r
- sc.RaiseOnDeserialized (obj, _context);\r
- }\r
-#endif\r
-\r
- private void AddFixup (BaseFixupRecord record)\r
- {\r
- record.ObjectToBeFixed.ChainFixup (record, true);\r
- record.ObjectRequired.ChainFixup (record, false);\r
- }\r
-\r
- public virtual void RecordArrayElementFixup (long arrayToBeFixed, int index, long objectRequired)\r
- {\r
- if (arrayToBeFixed <= 0) throw new ArgumentOutOfRangeException("arrayToBeFixed","The arrayToBeFixed parameter is less than or equal to zero");\r
- if (objectRequired <= 0) throw new ArgumentOutOfRangeException("objectRequired","The objectRequired parameter is less than or equal to zero");\r
- ArrayFixupRecord record = new ArrayFixupRecord(GetObjectRecord(arrayToBeFixed), index, GetObjectRecord(objectRequired));\r
- AddFixup (record);\r
- }\r
-\r
- public virtual void RecordArrayElementFixup (long arrayToBeFixed, int[] indices, long objectRequired)\r
- {\r
- if (arrayToBeFixed <= 0) throw new ArgumentOutOfRangeException("arrayToBeFixed","The arrayToBeFixed parameter is less than or equal to zero");\r
- if (objectRequired <= 0) throw new ArgumentOutOfRangeException("objectRequired","The objectRequired parameter is less than or equal to zero");\r
- if (indices == null) throw new ArgumentNullException("indices");\r
- MultiArrayFixupRecord record = new MultiArrayFixupRecord (GetObjectRecord(arrayToBeFixed), indices, GetObjectRecord(objectRequired));\r
- AddFixup (record);\r
- }\r
-\r
- public virtual void RecordDelayedFixup (long objectToBeFixed, string memberName, long objectRequired)\r
- {\r
- if (objectToBeFixed <= 0) throw new ArgumentOutOfRangeException("objectToBeFixed","The objectToBeFixed parameter is less than or equal to zero");\r
- if (objectRequired <= 0) throw new ArgumentOutOfRangeException("objectRequired","The objectRequired parameter is less than or equal to zero");\r
- if (memberName == null) throw new ArgumentNullException("memberName");\r
- DelayedFixupRecord record = new DelayedFixupRecord (GetObjectRecord(objectToBeFixed), memberName, GetObjectRecord(objectRequired));\r
- AddFixup (record);\r
- }\r
-\r
- public virtual void RecordFixup (long objectToBeFixed, MemberInfo member, long objectRequired)\r
- {\r
- if (objectToBeFixed <= 0) throw new ArgumentOutOfRangeException("objectToBeFixed","The objectToBeFixed parameter is less than or equal to zero");\r
- if (objectRequired <= 0) throw new ArgumentOutOfRangeException("objectRequired","The objectRequired parameter is less than or equal to zero");\r
- if (member == null) throw new ArgumentNullException("member");\r
- FixupRecord record = new FixupRecord (GetObjectRecord(objectToBeFixed), member, GetObjectRecord(objectRequired));\r
- AddFixup (record);\r
- }\r
-\r
- private void RegisterObjectInternal (object obj, ObjectRecord record)\r
- {\r
- if (obj == null) throw new ArgumentNullException("obj");\r
-\r
- if (record.IsRegistered)\r
- {\r
- if (record.OriginalObject != obj) throw new SerializationException ("An object with Id " + record.ObjectID + " has already been registered");\r
- else return;\r
- }\r
-\r
- record.ObjectInstance = obj;\r
- record.OriginalObject = obj;\r
-\r
- if (obj is IObjectReference) record.Status = ObjectRecordStatus.ReferenceUnsolved;\r
- else record.Status = ObjectRecordStatus.ReferenceSolved;\r
-\r
- if (_selector != null) {\r
- record.Surrogate = _selector.GetSurrogate (\r
- obj.GetType(), _context, out record.SurrogateSelector);\r
- if (record.Surrogate != null)\r
- record.Status = ObjectRecordStatus.ReferenceUnsolved;\r
- }\r
-\r
- record.DoFixups (true, this, false);\r
- record.DoFixups (false, this, false);\r
- _registeredObjectsCount++;\r
-\r
- // Adds the object to the chain of registered objects. This chain\r
- // is needed to be able to to perform the final fixups in the right order\r
-\r
- if (_objectRecordChain == null)\r
- {\r
- _objectRecordChain = record;\r
- _lastObjectRecord = record;\r
- }\r
- else \r
- {\r
- _lastObjectRecord.Next = record;\r
- _lastObjectRecord = record;\r
- }\r
- }\r
-\r
-\r
- public virtual void RegisterObject (object obj, long objectID)\r
- {\r
- if (obj == null) throw new ArgumentNullException("obj", "The obj parameter is null.");\r
- if (objectID <= 0) throw new ArgumentOutOfRangeException("objectID","The objectID parameter is less than or equal to zero");\r
- RegisterObjectInternal (obj, GetObjectRecord (objectID));\r
- }\r
-\r
- public void RegisterObject (object obj, long objectID, SerializationInfo info)\r
- {\r
- if (obj == null) throw new ArgumentNullException("obj", "The obj parameter is null.");\r
- if (objectID <= 0) throw new ArgumentOutOfRangeException("objectID","The objectID parameter is less than or equal to zero");\r
- \r
- ObjectRecord record = GetObjectRecord (objectID);\r
- record.Info = info;\r
- RegisterObjectInternal (obj, record);\r
- }\r
-\r
- public void RegisterObject (object obj, long objectID, SerializationInfo info, long idOfContainingObj, MemberInfo member)\r
- {\r
- RegisterObject (obj, objectID, info, idOfContainingObj, member, null);\r
- }\r
-\r
- public void RegisterObject( object obj, long objectID, SerializationInfo info, long idOfContainingObj, MemberInfo member, int[] arrayIndex)\r
- {\r
- if (obj == null) throw new ArgumentNullException("obj", "The obj parameter is null.");\r
- if (objectID <= 0) throw new ArgumentOutOfRangeException("objectID","The objectID parameter is less than or equal to zero");\r
-\r
- ObjectRecord record = GetObjectRecord (objectID);\r
- record.Info = info;\r
- record.IdOfContainingObj = idOfContainingObj;\r
- record.Member = member;\r
- record.ArrayIndex = arrayIndex;\r
- RegisterObjectInternal (obj, record);\r
- }\r
- }\r
-\r
-\r
-\r
- // Fixup types. There is a fixup class for each fixup type.\r
-\r
- // BaseFixupRecord\r
- // Base class for all fixups\r
-\r
- internal abstract class BaseFixupRecord\r
- {\r
- public BaseFixupRecord(ObjectRecord objectToBeFixed, ObjectRecord objectRequired)\r
- {\r
- ObjectToBeFixed = objectToBeFixed;\r
- ObjectRequired = objectRequired;\r
- }\r
-\r
- public bool DoFixup (ObjectManager manager, bool strict)\r
- {\r
- if (ObjectToBeFixed.IsRegistered && ObjectRequired.IsInstanceReady)\r
- {\r
- FixupImpl (manager);\r
- return true;\r
- }\r
- else if (strict)\r
- {\r
- if (!ObjectToBeFixed.IsRegistered) throw new SerializationException ("An object with ID " + ObjectToBeFixed.ObjectID + " was included in a fixup, but it has not been registered");\r
- else if (!ObjectRequired.IsRegistered) throw new SerializationException ("An object with ID " + ObjectRequired.ObjectID + " was included in a fixup, but it has not been registered");\r
- else return false;\r
- }\r
- else\r
- return false;\r
- }\r
-\r
- protected abstract void FixupImpl (ObjectManager manager);\r
-\r
- internal protected ObjectRecord ObjectToBeFixed;\r
- internal protected ObjectRecord ObjectRequired;\r
-\r
- public BaseFixupRecord NextSameContainer;\r
- public BaseFixupRecord NextSameRequired;\r
- }\r
-\r
- // ArrayFixupRecord\r
- // Fixup for assigning a value to one position of an array\r
-\r
- internal class ArrayFixupRecord : BaseFixupRecord\r
- {\r
- int _index;\r
-\r
- public ArrayFixupRecord (ObjectRecord objectToBeFixed, int index, ObjectRecord objectRequired): base (objectToBeFixed, objectRequired) {\r
- _index = index;\r
- }\r
-\r
- protected override void FixupImpl (ObjectManager manager) {\r
- Array array = (Array)ObjectToBeFixed.ObjectInstance;\r
- array.SetValue (ObjectRequired.ObjectInstance, _index);\r
- }\r
- }\r
-\r
- // MultiArrayFixupRecord\r
- // Fixup for assigning a value to several positions of an array\r
-\r
- internal class MultiArrayFixupRecord : BaseFixupRecord\r
- {\r
- int[] _indices;\r
-\r
- public MultiArrayFixupRecord (ObjectRecord objectToBeFixed, int[] indices, ObjectRecord objectRequired): base (objectToBeFixed, objectRequired) {\r
- _indices = indices;\r
- }\r
-\r
- protected override void FixupImpl (ObjectManager manager) {\r
- ObjectToBeFixed.SetArrayValue (manager, ObjectRequired.ObjectInstance, _indices);\r
- }\r
- }\r
-\r
- // FixupRecord\r
- // Fixup for assigning a value to a member of an object\r
-\r
- internal class FixupRecord: BaseFixupRecord\r
- {\r
- public MemberInfo _member;\r
-\r
- public FixupRecord (ObjectRecord objectToBeFixed, MemberInfo member, ObjectRecord objectRequired): base (objectToBeFixed, objectRequired) {\r
- _member = member;\r
- }\r
-\r
- protected override void FixupImpl (ObjectManager manager) {\r
- ObjectToBeFixed.SetMemberValue (manager, _member, ObjectRequired.ObjectInstance);\r
- }\r
- }\r
-\r
- // DelayedFixupRecord\r
- // Fixup for assigning a value to a SerializationInfo of an object\r
-\r
- internal class DelayedFixupRecord: BaseFixupRecord\r
- {\r
- public string _memberName;\r
-\r
- public DelayedFixupRecord (ObjectRecord objectToBeFixed, string memberName, ObjectRecord objectRequired): base (objectToBeFixed, objectRequired) {\r
- _memberName = memberName;\r
- }\r
-\r
- protected override void FixupImpl (ObjectManager manager) {\r
- ObjectToBeFixed.SetMemberValue (manager, _memberName, ObjectRequired.ObjectInstance);\r
- }\r
- }\r
-\r
- // Object Record\r
-\r
- internal enum ObjectRecordStatus: byte { Unregistered, ReferenceUnsolved, ReferenceSolvingDelayed, ReferenceSolved }\r
-\r
- internal class ObjectRecord\r
- {\r
- public ObjectRecordStatus Status = ObjectRecordStatus.Unregistered;\r
- public object OriginalObject;\r
- public object ObjectInstance;\r
- public long ObjectID;\r
- public SerializationInfo Info;\r
- public long IdOfContainingObj;\r
- public ISerializationSurrogate Surrogate;\r
- public ISurrogateSelector SurrogateSelector;\r
- public MemberInfo Member;\r
- public int[] ArrayIndex;\r
- public BaseFixupRecord FixupChainAsContainer;\r
- public BaseFixupRecord FixupChainAsRequired;\r
- public ObjectRecord Next;\r
-\r
- public void SetMemberValue (ObjectManager manager, MemberInfo member, object value)\r
- {\r
- if (member is FieldInfo)\r
- ((FieldInfo)member).SetValue (ObjectInstance, value);\r
- else if (member is PropertyInfo)\r
- ((PropertyInfo)member).SetValue (ObjectInstance, value, null);\r
- else throw new SerializationException ("Cannot perform fixup");\r
-\r
- if (Member != null)\r
- {\r
- ObjectRecord containerRecord = manager.GetObjectRecord (IdOfContainingObj);\r
- if (containerRecord.IsRegistered)\r
- containerRecord.SetMemberValue (manager, Member, ObjectInstance);\r
- }\r
- else if (ArrayIndex != null)\r
- {\r
- ObjectRecord containerRecord = manager.GetObjectRecord (IdOfContainingObj);\r
- if (containerRecord.IsRegistered)\r
- containerRecord.SetArrayValue (manager, ObjectInstance, ArrayIndex);\r
- }\r
- }\r
- public void SetArrayValue (ObjectManager manager, object value, int[] indices)\r
- {\r
- ((Array)ObjectInstance).SetValue (value, indices);\r
- }\r
-\r
- public void SetMemberValue (ObjectManager manager, string memberName, object value)\r
- {\r
- if (Info == null) throw new SerializationException ("Cannot perform fixup");\r
- Info.AddValue (memberName, value, value.GetType());\r
- }\r
-\r
- public bool IsInstanceReady\r
- {\r
- // Returns true if this object is ready to be assigned to a parent object.\r
- get\r
- {\r
- if (!IsRegistered) return false;\r
- if (IsUnsolvedObjectReference) return false;\r
-\r
- // Embedded value objects cannot be assigned to their containers until fully completed\r
- if (ObjectInstance.GetType ().IsValueType && (HasPendingFixups || Info != null))\r
- return false;\r
-\r
- return true;\r
- }\r
- }\r
-\r
- public bool IsUnsolvedObjectReference\r
- {\r
- get {\r
- return Status != ObjectRecordStatus.ReferenceSolved;\r
- }\r
- }\r
-\r
- public bool IsRegistered\r
- {\r
- get {\r
- return Status != ObjectRecordStatus.Unregistered;\r
- }\r
- }\r
-\r
- public bool DoFixups (bool asContainer, ObjectManager manager, bool strict)\r
- {\r
- BaseFixupRecord prevFixup = null;\r
- BaseFixupRecord fixup = asContainer ? FixupChainAsContainer : FixupChainAsRequired;\r
- bool allFixed = true;\r
-\r
- while (fixup != null)\r
- {\r
- if (fixup.DoFixup (manager, strict))\r
- {\r
- UnchainFixup (fixup, prevFixup, asContainer);\r
- if (asContainer) fixup.ObjectRequired.RemoveFixup (fixup, false);\r
- else fixup.ObjectToBeFixed.RemoveFixup (fixup, true);\r
- }\r
- else\r
- {\r
- prevFixup = fixup;\r
- allFixed = false;\r
- }\r
-\r
- fixup = asContainer ? fixup.NextSameContainer : fixup.NextSameRequired;\r
- }\r
- return allFixed;\r
- }\r
-\r
- public void RemoveFixup (BaseFixupRecord fixupToRemove, bool asContainer)\r
- {\r
- BaseFixupRecord prevFixup = null;\r
- BaseFixupRecord fixup = asContainer ? FixupChainAsContainer : FixupChainAsRequired;\r
- while (fixup != null)\r
- {\r
- if (fixup == fixupToRemove) \r
- {\r
- UnchainFixup (fixup, prevFixup, asContainer);\r
- return;\r
- }\r
- prevFixup = fixup;\r
- fixup = asContainer ? fixup.NextSameContainer : fixup.NextSameRequired;\r
- }\r
- }\r
-\r
- private void UnchainFixup (BaseFixupRecord fixup, BaseFixupRecord prevFixup, bool asContainer)\r
- {\r
- if (prevFixup == null) {\r
- if (asContainer) FixupChainAsContainer = fixup.NextSameContainer;\r
- else FixupChainAsRequired = fixup.NextSameRequired;\r
- }\r
- else {\r
- if (asContainer) prevFixup.NextSameContainer = fixup.NextSameContainer;\r
- else prevFixup.NextSameRequired = fixup.NextSameRequired;\r
- }\r
- }\r
-\r
- public void ChainFixup (BaseFixupRecord fixup, bool asContainer)\r
- {\r
- if (asContainer) \r
- {\r
- fixup.NextSameContainer = FixupChainAsContainer;\r
- FixupChainAsContainer = fixup;\r
- }\r
- else \r
- {\r
- fixup.NextSameRequired = FixupChainAsRequired;\r
- FixupChainAsRequired = fixup;\r
- }\r
- }\r
-\r
- public bool LoadData (ObjectManager manager, ISurrogateSelector selector, StreamingContext context)\r
- {\r
- if (Info != null)\r
- {\r
- if (Surrogate != null) {\r
- object new_obj = Surrogate.SetObjectData (ObjectInstance, Info, context, SurrogateSelector);\r
- if (new_obj != null)\r
- ObjectInstance = new_obj;\r
- Status = ObjectRecordStatus.ReferenceSolved;\r
- } else if (ObjectInstance is ISerializable) {\r
- object[] pars = new object[] {Info, context};\r
- ConstructorInfo con = ObjectInstance.GetType().GetConstructor (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof (SerializationInfo), typeof (StreamingContext) }, null );\r
- if (con == null) throw new SerializationException ("The constructor to deserialize an object of type " + ObjectInstance.GetType().FullName + " was not found.");\r
- con.Invoke (ObjectInstance, pars);\r
- } else {\r
- throw new SerializationException ("No surrogate selector was found for type " + ObjectInstance.GetType().FullName);\r
- }\r
-\r
- Info = null;\r
- }\r
-\r
- if (ObjectInstance is IObjectReference && Status != ObjectRecordStatus.ReferenceSolved)\r
- {\r
- try {\r
- ObjectInstance = ((IObjectReference)ObjectInstance).GetRealObject(context);\r
- int n = 100;\r
- while (ObjectInstance is IObjectReference && n > 0) {\r
- object ob = ((IObjectReference)ObjectInstance).GetRealObject (context);\r
- if (ob == ObjectInstance)\r
- break;\r
- ObjectInstance = ob;\r
- n--;\r
- }\r
- if (n == 0)\r
- throw new SerializationException ("The implementation of the IObjectReference interface returns too many nested references to other objects that implement IObjectReference.");\r
- \r
- Status = ObjectRecordStatus.ReferenceSolved;\r
- }\r
- catch (NullReferenceException) {\r
- // Give a second chance\r
- return false;\r
- }\r
- }\r
-\r
- if (Member != null)\r
- {\r
- // If this object is a value object embedded in another object, the parent\r
- // object must be updated\r
-\r
- ObjectRecord containerRecord = manager.GetObjectRecord (IdOfContainingObj);\r
- containerRecord.SetMemberValue (manager, Member, ObjectInstance);\r
- }\r
- else if (ArrayIndex != null)\r
- {\r
- ObjectRecord containerRecord = manager.GetObjectRecord (IdOfContainingObj);\r
- containerRecord.SetArrayValue (manager, ObjectInstance, ArrayIndex);\r
- }\r
-\r
- return true;\r
- }\r
-\r
- public bool HasPendingFixups\r
- {\r
- get { return FixupChainAsContainer != null; }\r
- }\r
- }\r
-}\r
+//
+// System.Runtime.Serialization.ObjectManager.cs
+//
+// Author: Lluis Sanchez Gual (lluis@ideary.com)
+//
+// (C) 2003 Lluis Sanchez Gual
+//
+
+//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using System.Reflection;
+
+namespace System.Runtime.Serialization
+{
+#if NET_2_0
+ [System.Runtime.InteropServices.ComVisibleAttribute (true)]
+#endif
+ public class ObjectManager
+ {
+ // All objects are chained in the same order as they have been registered
+ ObjectRecord _objectRecordChain = null;
+ ObjectRecord _lastObjectRecord = null;
+
+ ArrayList _deserializedRecords = new ArrayList();
+#if NET_2_0
+ ArrayList _onDeserializedCallbackRecords = new ArrayList();
+#endif
+ Hashtable _objectRecords = new Hashtable();
+ bool _finalFixup = false;
+
+ ISurrogateSelector _selector;
+ StreamingContext _context;
+ int _registeredObjectsCount = 0;
+
+ public ObjectManager(ISurrogateSelector selector, StreamingContext context)
+ {
+ _selector = selector;
+ _context = context;
+ }
+
+ public virtual void DoFixups()
+ {
+ _finalFixup = true;
+
+ try
+ {
+ if (_registeredObjectsCount < _objectRecords.Count)
+ throw new SerializationException ("There are some fixups that refer to objects that have not been registered");
+
+
+ ObjectRecord last = _lastObjectRecord;
+ bool firstCicle = true;
+
+ // Solve al pending fixups of all objects
+
+ ObjectRecord record = _objectRecordChain;
+ while (record != null)
+ {
+ bool ready = !(record.IsUnsolvedObjectReference && firstCicle);
+ if (ready) ready = record.DoFixups (true, this, true);
+ if (ready) ready = record.LoadData(this, _selector, _context);
+
+ ObjectRecord next;
+
+ if (ready)
+ {
+ if (record.OriginalObject is IDeserializationCallback)
+ _deserializedRecords.Add (record);
+
+#if NET_2_0
+ SerializationCallbacks sc = SerializationCallbacks
+ .GetSerializationCallbacks (record.OriginalObject.GetType ());
+ if (sc.HasDeserializedCallbacks)
+ _onDeserializedCallbackRecords.Add (record);
+#endif
+ next = record.Next;
+ }
+ else
+ {
+ // There must be an unresolved IObjectReference instance.
+ // Chain the record at the end so it is solved later
+
+ if ((record.ObjectInstance is IObjectReference) && !firstCicle)
+ {
+ if (record.Status == ObjectRecordStatus.ReferenceSolvingDelayed)
+ throw new SerializationException ("The object with ID " + record.ObjectID + " could not be resolved");
+ else
+ record.Status = ObjectRecordStatus.ReferenceSolvingDelayed;
+ }
+
+ if (record != _lastObjectRecord) {
+ next = record.Next;
+ record.Next = null;
+ _lastObjectRecord.Next = record;
+ _lastObjectRecord = record;
+ }
+ else
+ next = record;
+ }
+
+ if (record == last) firstCicle = false;
+ record = next;
+ }
+ }
+ finally
+ {
+ _finalFixup = false;
+ }
+ }
+
+ internal ObjectRecord GetObjectRecord (long objectID)
+ {
+ ObjectRecord rec = (ObjectRecord)_objectRecords[objectID];
+ if (rec == null)
+ {
+ if (_finalFixup) throw new SerializationException ("The object with Id " + objectID + " has not been registered");
+ rec = new ObjectRecord();
+ rec.ObjectID = objectID;
+ _objectRecords[objectID] = rec;
+ }
+ if (!rec.IsRegistered && _finalFixup) throw new SerializationException ("The object with Id " + objectID + " has not been registered");
+ return rec;
+ }
+
+ public virtual object GetObject (long objectID)
+ {
+ if (objectID <= 0) throw new ArgumentOutOfRangeException("objectID","The objectID parameter is less than or equal to zero");
+ ObjectRecord rec = (ObjectRecord)_objectRecords[objectID];
+ if (rec == null || !rec.IsRegistered) return null;
+ else return rec.ObjectInstance;
+ }
+
+ public virtual void RaiseDeserializationEvent ()
+ {
+#if NET_2_0
+ for (int i = _onDeserializedCallbackRecords.Count-1; i >= 0; i--)
+ {
+ ObjectRecord record = (ObjectRecord) _onDeserializedCallbackRecords [i];
+ RaiseOnDeserializedEvent (record.OriginalObject);
+ }
+#endif
+ for (int i = _deserializedRecords.Count-1; i >= 0; i--)
+ {
+ ObjectRecord record = (ObjectRecord) _deserializedRecords [i];
+ IDeserializationCallback obj = record.OriginalObject as IDeserializationCallback;
+ if (obj != null) obj.OnDeserialization (this);
+ }
+
+ }
+
+#if NET_2_0
+ public void RaiseOnDeserializingEvent (object obj)
+ {
+ SerializationCallbacks sc = SerializationCallbacks
+ .GetSerializationCallbacks (obj.GetType ());
+ sc.RaiseOnDeserializing (obj, _context);
+ }
+
+ void RaiseOnDeserializedEvent (object obj)
+ {
+ SerializationCallbacks sc = SerializationCallbacks
+ .GetSerializationCallbacks (obj.GetType ());
+ sc.RaiseOnDeserialized (obj, _context);
+ }
+#endif
+
+ private void AddFixup (BaseFixupRecord record)
+ {
+ record.ObjectToBeFixed.ChainFixup (record, true);
+ record.ObjectRequired.ChainFixup (record, false);
+ }
+
+ public virtual void RecordArrayElementFixup (long arrayToBeFixed, int index, long objectRequired)
+ {
+ if (arrayToBeFixed <= 0) throw new ArgumentOutOfRangeException("arrayToBeFixed","The arrayToBeFixed parameter is less than or equal to zero");
+ if (objectRequired <= 0) throw new ArgumentOutOfRangeException("objectRequired","The objectRequired parameter is less than or equal to zero");
+ ArrayFixupRecord record = new ArrayFixupRecord(GetObjectRecord(arrayToBeFixed), index, GetObjectRecord(objectRequired));
+ AddFixup (record);
+ }
+
+ public virtual void RecordArrayElementFixup (long arrayToBeFixed, int[] indices, long objectRequired)
+ {
+ if (arrayToBeFixed <= 0) throw new ArgumentOutOfRangeException("arrayToBeFixed","The arrayToBeFixed parameter is less than or equal to zero");
+ if (objectRequired <= 0) throw new ArgumentOutOfRangeException("objectRequired","The objectRequired parameter is less than or equal to zero");
+ if (indices == null) throw new ArgumentNullException("indices");
+ MultiArrayFixupRecord record = new MultiArrayFixupRecord (GetObjectRecord(arrayToBeFixed), indices, GetObjectRecord(objectRequired));
+ AddFixup (record);
+ }
+
+ public virtual void RecordDelayedFixup (long objectToBeFixed, string memberName, long objectRequired)
+ {
+ if (objectToBeFixed <= 0) throw new ArgumentOutOfRangeException("objectToBeFixed","The objectToBeFixed parameter is less than or equal to zero");
+ if (objectRequired <= 0) throw new ArgumentOutOfRangeException("objectRequired","The objectRequired parameter is less than or equal to zero");
+ if (memberName == null) throw new ArgumentNullException("memberName");
+ DelayedFixupRecord record = new DelayedFixupRecord (GetObjectRecord(objectToBeFixed), memberName, GetObjectRecord(objectRequired));
+ AddFixup (record);
+ }
+
+ public virtual void RecordFixup (long objectToBeFixed, MemberInfo member, long objectRequired)
+ {
+ if (objectToBeFixed <= 0) throw new ArgumentOutOfRangeException("objectToBeFixed","The objectToBeFixed parameter is less than or equal to zero");
+ if (objectRequired <= 0) throw new ArgumentOutOfRangeException("objectRequired","The objectRequired parameter is less than or equal to zero");
+ if (member == null) throw new ArgumentNullException("member");
+ FixupRecord record = new FixupRecord (GetObjectRecord(objectToBeFixed), member, GetObjectRecord(objectRequired));
+ AddFixup (record);
+ }
+
+ private void RegisterObjectInternal (object obj, ObjectRecord record)
+ {
+ if (obj == null) throw new ArgumentNullException("obj");
+
+ if (record.IsRegistered)
+ {
+ if (record.OriginalObject != obj) throw new SerializationException ("An object with Id " + record.ObjectID + " has already been registered");
+ else return;
+ }
+
+ record.ObjectInstance = obj;
+ record.OriginalObject = obj;
+
+ if (obj is IObjectReference) record.Status = ObjectRecordStatus.ReferenceUnsolved;
+ else record.Status = ObjectRecordStatus.ReferenceSolved;
+
+ if (_selector != null) {
+ record.Surrogate = _selector.GetSurrogate (
+ obj.GetType(), _context, out record.SurrogateSelector);
+ if (record.Surrogate != null)
+ record.Status = ObjectRecordStatus.ReferenceUnsolved;
+ }
+
+ record.DoFixups (true, this, false);
+ record.DoFixups (false, this, false);
+ _registeredObjectsCount++;
+
+ // Adds the object to the chain of registered objects. This chain
+ // is needed to be able to to perform the final fixups in the right order
+
+ if (_objectRecordChain == null)
+ {
+ _objectRecordChain = record;
+ _lastObjectRecord = record;
+ }
+ else
+ {
+ _lastObjectRecord.Next = record;
+ _lastObjectRecord = record;
+ }
+ }
+
+
+ public virtual void RegisterObject (object obj, long objectID)
+ {
+ if (obj == null) throw new ArgumentNullException("obj", "The obj parameter is null.");
+ if (objectID <= 0) throw new ArgumentOutOfRangeException("objectID","The objectID parameter is less than or equal to zero");
+ RegisterObjectInternal (obj, GetObjectRecord (objectID));
+ }
+
+ public void RegisterObject (object obj, long objectID, SerializationInfo info)
+ {
+ if (obj == null) throw new ArgumentNullException("obj", "The obj parameter is null.");
+ if (objectID <= 0) throw new ArgumentOutOfRangeException("objectID","The objectID parameter is less than or equal to zero");
+
+ ObjectRecord record = GetObjectRecord (objectID);
+ record.Info = info;
+ RegisterObjectInternal (obj, record);
+ }
+
+ public void RegisterObject (object obj, long objectID, SerializationInfo info, long idOfContainingObj, MemberInfo member)
+ {
+ RegisterObject (obj, objectID, info, idOfContainingObj, member, null);
+ }
+
+ public void RegisterObject( object obj, long objectID, SerializationInfo info, long idOfContainingObj, MemberInfo member, int[] arrayIndex)
+ {
+ if (obj == null) throw new ArgumentNullException("obj", "The obj parameter is null.");
+ if (objectID <= 0) throw new ArgumentOutOfRangeException("objectID","The objectID parameter is less than or equal to zero");
+
+ ObjectRecord record = GetObjectRecord (objectID);
+ record.Info = info;
+ record.IdOfContainingObj = idOfContainingObj;
+ record.Member = member;
+ record.ArrayIndex = arrayIndex;
+ RegisterObjectInternal (obj, record);
+ }
+ }
+
+
+
+ // Fixup types. There is a fixup class for each fixup type.
+
+ // BaseFixupRecord
+ // Base class for all fixups
+
+ internal abstract class BaseFixupRecord
+ {
+ public BaseFixupRecord(ObjectRecord objectToBeFixed, ObjectRecord objectRequired)
+ {
+ ObjectToBeFixed = objectToBeFixed;
+ ObjectRequired = objectRequired;
+ }
+
+ public bool DoFixup (ObjectManager manager, bool strict)
+ {
+ if (ObjectToBeFixed.IsRegistered && ObjectRequired.IsInstanceReady)
+ {
+ FixupImpl (manager);
+ return true;
+ }
+ else if (strict)
+ {
+ if (!ObjectToBeFixed.IsRegistered) throw new SerializationException ("An object with ID " + ObjectToBeFixed.ObjectID + " was included in a fixup, but it has not been registered");
+ else if (!ObjectRequired.IsRegistered) throw new SerializationException ("An object with ID " + ObjectRequired.ObjectID + " was included in a fixup, but it has not been registered");
+ else return false;
+ }
+ else
+ return false;
+ }
+
+ protected abstract void FixupImpl (ObjectManager manager);
+
+ internal protected ObjectRecord ObjectToBeFixed;
+ internal protected ObjectRecord ObjectRequired;
+
+ public BaseFixupRecord NextSameContainer;
+ public BaseFixupRecord NextSameRequired;
+ }
+
+ // ArrayFixupRecord
+ // Fixup for assigning a value to one position of an array
+
+ internal class ArrayFixupRecord : BaseFixupRecord
+ {
+ int _index;
+
+ public ArrayFixupRecord (ObjectRecord objectToBeFixed, int index, ObjectRecord objectRequired): base (objectToBeFixed, objectRequired) {
+ _index = index;
+ }
+
+ protected override void FixupImpl (ObjectManager manager) {
+ Array array = (Array)ObjectToBeFixed.ObjectInstance;
+ array.SetValue (ObjectRequired.ObjectInstance, _index);
+ }
+ }
+
+ // MultiArrayFixupRecord
+ // Fixup for assigning a value to several positions of an array
+
+ internal class MultiArrayFixupRecord : BaseFixupRecord
+ {
+ int[] _indices;
+
+ public MultiArrayFixupRecord (ObjectRecord objectToBeFixed, int[] indices, ObjectRecord objectRequired): base (objectToBeFixed, objectRequired) {
+ _indices = indices;
+ }
+
+ protected override void FixupImpl (ObjectManager manager) {
+ ObjectToBeFixed.SetArrayValue (manager, ObjectRequired.ObjectInstance, _indices);
+ }
+ }
+
+ // FixupRecord
+ // Fixup for assigning a value to a member of an object
+
+ internal class FixupRecord: BaseFixupRecord
+ {
+ public MemberInfo _member;
+
+ public FixupRecord (ObjectRecord objectToBeFixed, MemberInfo member, ObjectRecord objectRequired): base (objectToBeFixed, objectRequired) {
+ _member = member;
+ }
+
+ protected override void FixupImpl (ObjectManager manager) {
+ ObjectToBeFixed.SetMemberValue (manager, _member, ObjectRequired.ObjectInstance);
+ }
+ }
+
+ // DelayedFixupRecord
+ // Fixup for assigning a value to a SerializationInfo of an object
+
+ internal class DelayedFixupRecord: BaseFixupRecord
+ {
+ public string _memberName;
+
+ public DelayedFixupRecord (ObjectRecord objectToBeFixed, string memberName, ObjectRecord objectRequired): base (objectToBeFixed, objectRequired) {
+ _memberName = memberName;
+ }
+
+ protected override void FixupImpl (ObjectManager manager) {
+ ObjectToBeFixed.SetMemberValue (manager, _memberName, ObjectRequired.ObjectInstance);
+ }
+ }
+
+ // Object Record
+
+ internal enum ObjectRecordStatus: byte { Unregistered, ReferenceUnsolved, ReferenceSolvingDelayed, ReferenceSolved }
+
+ internal class ObjectRecord
+ {
+ public ObjectRecordStatus Status = ObjectRecordStatus.Unregistered;
+ public object OriginalObject;
+ public object ObjectInstance;
+ public long ObjectID;
+ public SerializationInfo Info;
+ public long IdOfContainingObj;
+ public ISerializationSurrogate Surrogate;
+ public ISurrogateSelector SurrogateSelector;
+ public MemberInfo Member;
+ public int[] ArrayIndex;
+ public BaseFixupRecord FixupChainAsContainer;
+ public BaseFixupRecord FixupChainAsRequired;
+ public ObjectRecord Next;
+
+ public void SetMemberValue (ObjectManager manager, MemberInfo member, object value)
+ {
+ if (member is FieldInfo)
+ ((FieldInfo)member).SetValue (ObjectInstance, value);
+ else if (member is PropertyInfo)
+ ((PropertyInfo)member).SetValue (ObjectInstance, value, null);
+ else throw new SerializationException ("Cannot perform fixup");
+
+ if (Member != null)
+ {
+ ObjectRecord containerRecord = manager.GetObjectRecord (IdOfContainingObj);
+ if (containerRecord.IsRegistered)
+ containerRecord.SetMemberValue (manager, Member, ObjectInstance);
+ }
+ else if (ArrayIndex != null)
+ {
+ ObjectRecord containerRecord = manager.GetObjectRecord (IdOfContainingObj);
+ if (containerRecord.IsRegistered)
+ containerRecord.SetArrayValue (manager, ObjectInstance, ArrayIndex);
+ }
+ }
+ public void SetArrayValue (ObjectManager manager, object value, int[] indices)
+ {
+ ((Array)ObjectInstance).SetValue (value, indices);
+ }
+
+ public void SetMemberValue (ObjectManager manager, string memberName, object value)
+ {
+ if (Info == null) throw new SerializationException ("Cannot perform fixup");
+ Info.AddValue (memberName, value, value.GetType());
+ }
+
+ public bool IsInstanceReady
+ {
+ // Returns true if this object is ready to be assigned to a parent object.
+ get
+ {
+ if (!IsRegistered) return false;
+ if (IsUnsolvedObjectReference) return false;
+
+ // Embedded value objects cannot be assigned to their containers until fully completed
+ if (ObjectInstance.GetType ().IsValueType && (HasPendingFixups || Info != null))
+ return false;
+
+ return true;
+ }
+ }
+
+ public bool IsUnsolvedObjectReference
+ {
+ get {
+ return Status != ObjectRecordStatus.ReferenceSolved;
+ }
+ }
+
+ public bool IsRegistered
+ {
+ get {
+ return Status != ObjectRecordStatus.Unregistered;
+ }
+ }
+
+ public bool DoFixups (bool asContainer, ObjectManager manager, bool strict)
+ {
+ BaseFixupRecord prevFixup = null;
+ BaseFixupRecord fixup = asContainer ? FixupChainAsContainer : FixupChainAsRequired;
+ bool allFixed = true;
+
+ while (fixup != null)
+ {
+ if (fixup.DoFixup (manager, strict))
+ {
+ UnchainFixup (fixup, prevFixup, asContainer);
+ if (asContainer) fixup.ObjectRequired.RemoveFixup (fixup, false);
+ else fixup.ObjectToBeFixed.RemoveFixup (fixup, true);
+ }
+ else
+ {
+ prevFixup = fixup;
+ allFixed = false;
+ }
+
+ fixup = asContainer ? fixup.NextSameContainer : fixup.NextSameRequired;
+ }
+ return allFixed;
+ }
+
+ public void RemoveFixup (BaseFixupRecord fixupToRemove, bool asContainer)
+ {
+ BaseFixupRecord prevFixup = null;
+ BaseFixupRecord fixup = asContainer ? FixupChainAsContainer : FixupChainAsRequired;
+ while (fixup != null)
+ {
+ if (fixup == fixupToRemove)
+ {
+ UnchainFixup (fixup, prevFixup, asContainer);
+ return;
+ }
+ prevFixup = fixup;
+ fixup = asContainer ? fixup.NextSameContainer : fixup.NextSameRequired;
+ }
+ }
+
+ private void UnchainFixup (BaseFixupRecord fixup, BaseFixupRecord prevFixup, bool asContainer)
+ {
+ if (prevFixup == null) {
+ if (asContainer) FixupChainAsContainer = fixup.NextSameContainer;
+ else FixupChainAsRequired = fixup.NextSameRequired;
+ }
+ else {
+ if (asContainer) prevFixup.NextSameContainer = fixup.NextSameContainer;
+ else prevFixup.NextSameRequired = fixup.NextSameRequired;
+ }
+ }
+
+ public void ChainFixup (BaseFixupRecord fixup, bool asContainer)
+ {
+ if (asContainer)
+ {
+ fixup.NextSameContainer = FixupChainAsContainer;
+ FixupChainAsContainer = fixup;
+ }
+ else
+ {
+ fixup.NextSameRequired = FixupChainAsRequired;
+ FixupChainAsRequired = fixup;
+ }
+ }
+
+ public bool LoadData (ObjectManager manager, ISurrogateSelector selector, StreamingContext context)
+ {
+ if (Info != null)
+ {
+ if (Surrogate != null) {
+ object new_obj = Surrogate.SetObjectData (ObjectInstance, Info, context, SurrogateSelector);
+ if (new_obj != null)
+ ObjectInstance = new_obj;
+ Status = ObjectRecordStatus.ReferenceSolved;
+ } else if (ObjectInstance is ISerializable) {
+ object[] pars = new object[] {Info, context};
+ ConstructorInfo con = ObjectInstance.GetType().GetConstructor (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof (SerializationInfo), typeof (StreamingContext) }, null );
+ if (con == null) throw new SerializationException ("The constructor to deserialize an object of type " + ObjectInstance.GetType().FullName + " was not found.");
+ con.Invoke (ObjectInstance, pars);
+ } else {
+ throw new SerializationException ("No surrogate selector was found for type " + ObjectInstance.GetType().FullName);
+ }
+
+ Info = null;
+ }
+
+ if (ObjectInstance is IObjectReference && Status != ObjectRecordStatus.ReferenceSolved)
+ {
+ try {
+ ObjectInstance = ((IObjectReference)ObjectInstance).GetRealObject(context);
+ int n = 100;
+ while (ObjectInstance is IObjectReference && n > 0) {
+ object ob = ((IObjectReference)ObjectInstance).GetRealObject (context);
+ if (ob == ObjectInstance)
+ break;
+ ObjectInstance = ob;
+ n--;
+ }
+ if (n == 0)
+ throw new SerializationException ("The implementation of the IObjectReference interface returns too many nested references to other objects that implement IObjectReference.");
+
+ Status = ObjectRecordStatus.ReferenceSolved;
+ }
+ catch (NullReferenceException) {
+ // Give a second chance
+ return false;
+ }
+ }
+
+ if (Member != null)
+ {
+ // If this object is a value object embedded in another object, the parent
+ // object must be updated
+
+ ObjectRecord containerRecord = manager.GetObjectRecord (IdOfContainingObj);
+ containerRecord.SetMemberValue (manager, Member, ObjectInstance);
+ }
+ else if (ArrayIndex != null)
+ {
+ ObjectRecord containerRecord = manager.GetObjectRecord (IdOfContainingObj);
+ containerRecord.SetArrayValue (manager, ObjectInstance, ArrayIndex);
+ }
+
+ return true;
+ }
+
+ public bool HasPendingFixups
+ {
+ get { return FixupChainAsContainer != null; }
+ }
+ }
+}