Implemented overloaded versions of Parse and TryParse functions for BigInteger.
[mono.git] / mcs / class / corlib / System.Runtime.Serialization / ObjectManager.cs
1 //
2 // System.Runtime.Serialization.ObjectManager.cs
3 //
4 // Author: Lluis Sanchez Gual (lluis@ideary.com)
5 //
6 // (C) 2003 Lluis Sanchez Gual
7 //
8
9 //
10 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System;
33 using System.Collections;
34 using System.Reflection;
35
36 namespace System.Runtime.Serialization
37 {
38         [System.Runtime.InteropServices.ComVisibleAttribute (true)]
39         public class ObjectManager
40         {
41                 // All objects are chained in the same order as they have been registered
42                 ObjectRecord _objectRecordChain = null;
43                 ObjectRecord _lastObjectRecord = null;
44
45                 ArrayList _deserializedRecords = new ArrayList();
46                 ArrayList _onDeserializedCallbackRecords = new ArrayList();
47                 Hashtable _objectRecords = new Hashtable();
48                 bool _finalFixup = false;
49
50                 ISurrogateSelector _selector;
51                 StreamingContext _context;
52                 int _registeredObjectsCount = 0;
53
54                 public ObjectManager(ISurrogateSelector selector, StreamingContext context)
55                 {
56                         _selector = selector;
57                         _context = context;
58                 }
59
60                 public virtual void DoFixups()
61                 {
62                         _finalFixup = true;
63
64                         try
65                         {
66                                 if (_registeredObjectsCount < _objectRecords.Count)
67                                         throw new SerializationException ("There are some fixups that refer to objects that have not been registered");
68
69
70                                 ObjectRecord last = _lastObjectRecord;
71                                 bool firstCicle = true;
72
73                                 // Solve al pending fixups of all objects
74
75                                 ObjectRecord record = _objectRecordChain;
76                                 while (record != null)
77                                 {
78                                         bool ready = !(record.IsUnsolvedObjectReference && firstCicle);
79                                         if (ready) ready = record.DoFixups (true, this, true);
80                                         if (ready) ready = record.LoadData(this, _selector, _context);
81
82                                         ObjectRecord next;
83
84                                         if (ready)
85                                         {
86                                                 if (record.OriginalObject is IDeserializationCallback)
87                                                         _deserializedRecords.Add (record);
88
89                                                 SerializationCallbacks sc = SerializationCallbacks
90                                                         .GetSerializationCallbacks (record.OriginalObject.GetType ());
91                                                 if (sc.HasDeserializedCallbacks)
92                                                         _onDeserializedCallbackRecords.Add (record);
93                                                 next = record.Next;
94                                         }
95                                         else
96                                         {
97                                                 // There must be an unresolved IObjectReference instance.
98                                                 // Chain the record at the end so it is solved later
99
100                                                 if ((record.ObjectInstance is IObjectReference) && !firstCicle)
101                                                 {
102                                                         if (record.Status == ObjectRecordStatus.ReferenceSolvingDelayed)
103                                                                 throw new SerializationException ("The object with ID " + record.ObjectID + " could not be resolved");
104                                                         else
105                                                                 record.Status = ObjectRecordStatus.ReferenceSolvingDelayed;
106                                                 }
107
108                                                 if (record != _lastObjectRecord) {
109                                                         next = record.Next;
110                                                         record.Next = null;
111                                                         _lastObjectRecord.Next = record;
112                                                         _lastObjectRecord = record;
113                                                 }
114                                                 else
115                                                         next = record;
116                                         }
117
118                                         if (record == last) firstCicle = false;
119                                         record = next;
120                                 }
121                         }
122                         finally
123                         {
124                                 _finalFixup = false;
125                         }
126                 }
127
128                 internal ObjectRecord GetObjectRecord (long objectID)
129                 {
130                         ObjectRecord rec = (ObjectRecord)_objectRecords[objectID];
131                         if (rec == null)
132                         {
133                                 if (_finalFixup) throw new SerializationException ("The object with Id " + objectID + " has not been registered");
134                                 rec = new ObjectRecord();
135                                 rec.ObjectID = objectID;
136                                 _objectRecords[objectID] = rec;
137                         }
138                         if (!rec.IsRegistered && _finalFixup) throw new SerializationException ("The object with Id " + objectID + " has not been registered");
139                         return rec;
140                 }
141
142                 public virtual object GetObject (long objectID)
143                 {
144                         if (objectID <= 0) throw new ArgumentOutOfRangeException("objectID","The objectID parameter is less than or equal to zero");
145                         ObjectRecord rec = (ObjectRecord)_objectRecords[objectID];
146                         if (rec == null || !rec.IsRegistered) return null;
147                         else return rec.ObjectInstance;
148                 }
149
150                 public virtual void RaiseDeserializationEvent ()
151                 {
152                         for (int i = _onDeserializedCallbackRecords.Count-1; i >= 0; i--)
153                         {
154                                 ObjectRecord record = (ObjectRecord) _onDeserializedCallbackRecords [i];
155                                 RaiseOnDeserializedEvent (record.OriginalObject);
156                         }
157                         for (int i = _deserializedRecords.Count-1; i >= 0; i--)
158                         {
159                                 ObjectRecord record = (ObjectRecord) _deserializedRecords [i];
160                                 IDeserializationCallback obj = record.OriginalObject as IDeserializationCallback;
161                                 if (obj != null) obj.OnDeserialization (this);
162                         }
163
164                 }
165
166                 public void RaiseOnDeserializingEvent (object obj)
167                 {
168                         SerializationCallbacks sc = SerializationCallbacks
169                                 .GetSerializationCallbacks (obj.GetType ());
170                         sc.RaiseOnDeserializing (obj, _context);
171                 }
172
173                 void RaiseOnDeserializedEvent (object obj)
174                 {
175                         SerializationCallbacks sc = SerializationCallbacks
176                                 .GetSerializationCallbacks (obj.GetType ());
177                         sc.RaiseOnDeserialized (obj, _context);
178                 }
179
180                 private void AddFixup (BaseFixupRecord record)
181                 {
182                         record.ObjectToBeFixed.ChainFixup (record, true);
183                         record.ObjectRequired.ChainFixup (record, false);
184                 }
185
186                 public virtual void RecordArrayElementFixup (long arrayToBeFixed, int index, long objectRequired)
187                 {
188                         if (arrayToBeFixed <= 0) throw new ArgumentOutOfRangeException("arrayToBeFixed","The arrayToBeFixed parameter is less than or equal to zero");
189                         if (objectRequired <= 0) throw new ArgumentOutOfRangeException("objectRequired","The objectRequired parameter is less than or equal to zero");
190                         ArrayFixupRecord record = new ArrayFixupRecord(GetObjectRecord(arrayToBeFixed), index, GetObjectRecord(objectRequired));
191                         AddFixup (record);
192                 }
193
194                 public virtual void RecordArrayElementFixup (long arrayToBeFixed, int[] indices, long objectRequired)
195                 {
196                         if (arrayToBeFixed <= 0) throw new ArgumentOutOfRangeException("arrayToBeFixed","The arrayToBeFixed parameter is less than or equal to zero");
197                         if (objectRequired <= 0) throw new ArgumentOutOfRangeException("objectRequired","The objectRequired parameter is less than or equal to zero");
198                         if (indices == null) throw new ArgumentNullException("indices");
199                         MultiArrayFixupRecord record = new MultiArrayFixupRecord (GetObjectRecord(arrayToBeFixed), indices, GetObjectRecord(objectRequired));
200                         AddFixup (record);
201                 }
202
203                 public virtual void RecordDelayedFixup (long objectToBeFixed, string memberName, long objectRequired)
204                 {
205                         if (objectToBeFixed <= 0) throw new ArgumentOutOfRangeException("objectToBeFixed","The objectToBeFixed parameter is less than or equal to zero");
206                         if (objectRequired <= 0) throw new ArgumentOutOfRangeException("objectRequired","The objectRequired parameter is less than or equal to zero");
207                         if (memberName == null) throw new ArgumentNullException("memberName");
208                         DelayedFixupRecord record = new DelayedFixupRecord (GetObjectRecord(objectToBeFixed), memberName, GetObjectRecord(objectRequired));
209                         AddFixup (record);
210                 }
211
212                 public virtual void RecordFixup (long objectToBeFixed, MemberInfo member, long objectRequired)
213                 {
214                         if (objectToBeFixed <= 0) throw new ArgumentOutOfRangeException("objectToBeFixed","The objectToBeFixed parameter is less than or equal to zero");
215                         if (objectRequired <= 0) throw new ArgumentOutOfRangeException("objectRequired","The objectRequired parameter is less than or equal to zero");
216                         if (member == null) throw new ArgumentNullException("member");
217                         FixupRecord record = new FixupRecord (GetObjectRecord(objectToBeFixed), member, GetObjectRecord(objectRequired));
218                         AddFixup (record);
219                 }
220
221                 private void RegisterObjectInternal (object obj, ObjectRecord record)
222                 {
223                         if (obj == null) throw new ArgumentNullException("obj");
224
225                         if (record.IsRegistered)
226                         {
227                                 if (record.OriginalObject != obj) throw new SerializationException ("An object with Id " + record.ObjectID + " has already been registered");
228                                 else return;
229                         }
230
231                         record.ObjectInstance = obj;
232                         record.OriginalObject = obj;
233
234                         if (obj is IObjectReference) record.Status = ObjectRecordStatus.ReferenceUnsolved;
235                         else record.Status = ObjectRecordStatus.ReferenceSolved;
236
237                         if (_selector != null) {
238                                 record.Surrogate = _selector.GetSurrogate (
239                                         obj.GetType(), _context, out record.SurrogateSelector);
240                                 if (record.Surrogate != null)
241                                         record.Status = ObjectRecordStatus.ReferenceUnsolved;
242                         }
243
244                         record.DoFixups (true, this, false);
245                         record.DoFixups (false, this, false);
246                         _registeredObjectsCount++;
247
248                         // Adds the object to the chain of registered objects. This chain
249                         // is needed to be able to to perform the final fixups in the right order
250
251                         if (_objectRecordChain == null)
252                         {
253                                 _objectRecordChain = record;
254                                 _lastObjectRecord = record;
255                         }
256                         else 
257                         {
258                                 _lastObjectRecord.Next = record;
259                                 _lastObjectRecord = record;
260                         }
261                 }
262
263
264                 public virtual void RegisterObject (object obj, long objectID)
265                 {
266                         if (obj == null) throw new ArgumentNullException("obj", "The obj parameter is null.");
267                         if (objectID <= 0) throw new ArgumentOutOfRangeException("objectID","The objectID parameter is less than or equal to zero");
268                         RegisterObjectInternal (obj, GetObjectRecord (objectID));
269                 }
270
271                 public void RegisterObject (object obj, long objectID, SerializationInfo info)
272                 {
273                         if (obj == null) throw new ArgumentNullException("obj", "The obj parameter is null.");
274                         if (objectID <= 0) throw new ArgumentOutOfRangeException("objectID","The objectID parameter is less than or equal to zero");
275                         
276                         ObjectRecord record = GetObjectRecord (objectID);
277                         record.Info = info;
278                         RegisterObjectInternal (obj, record);
279                 }
280
281                 public void RegisterObject (object obj, long objectID, SerializationInfo info, long idOfContainingObj, MemberInfo member)
282                 {
283                         RegisterObject (obj, objectID, info, idOfContainingObj, member, null);
284                 }
285
286                 public void RegisterObject( object obj, long objectID, SerializationInfo info, long idOfContainingObj, MemberInfo member, int[] arrayIndex)
287                 {
288                         if (obj == null) throw new ArgumentNullException("obj", "The obj parameter is null.");
289                         if (objectID <= 0) throw new ArgumentOutOfRangeException("objectID","The objectID parameter is less than or equal to zero");
290
291                         ObjectRecord record = GetObjectRecord (objectID);
292                         record.Info = info;
293                         record.IdOfContainingObj = idOfContainingObj;
294                         record.Member = member;
295                         record.ArrayIndex = arrayIndex;
296                         RegisterObjectInternal (obj, record);
297                 }
298         }
299
300
301
302         // Fixup types. There is a fixup class for each fixup type.
303
304         // BaseFixupRecord
305         // Base class for all fixups
306
307         internal abstract class BaseFixupRecord
308         {
309                 public BaseFixupRecord(ObjectRecord objectToBeFixed, ObjectRecord objectRequired)
310                 {
311                         ObjectToBeFixed = objectToBeFixed;
312                         ObjectRequired = objectRequired;
313                 }
314
315                 public bool DoFixup (ObjectManager manager, bool strict)
316                 {
317                         if (ObjectToBeFixed.IsRegistered && ObjectRequired.IsInstanceReady)
318                         {
319                                 FixupImpl (manager);
320                                 return true;
321                         }
322                         else if (strict)
323                         {
324                                 if (!ObjectToBeFixed.IsRegistered) throw new SerializationException ("An object with ID " + ObjectToBeFixed.ObjectID + " was included in a fixup, but it has not been registered");
325                                 else if (!ObjectRequired.IsRegistered) throw new SerializationException ("An object with ID " + ObjectRequired.ObjectID + " was included in a fixup, but it has not been registered");
326                                 else return false;
327                         }
328                         else
329                                 return false;
330                 }
331
332                 protected abstract void FixupImpl (ObjectManager manager);
333
334                 internal protected ObjectRecord ObjectToBeFixed;
335                 internal protected ObjectRecord ObjectRequired;
336
337                 public BaseFixupRecord NextSameContainer;
338                 public BaseFixupRecord NextSameRequired;
339         }
340
341         // ArrayFixupRecord
342         // Fixup for assigning a value to one position of an array
343
344         internal class ArrayFixupRecord : BaseFixupRecord
345         {
346                 int _index;
347
348                 public ArrayFixupRecord (ObjectRecord objectToBeFixed, int index, ObjectRecord objectRequired): base (objectToBeFixed, objectRequired) {
349                         _index = index;
350                 }
351
352                 protected override void FixupImpl (ObjectManager manager) {
353                         Array array = (Array)ObjectToBeFixed.ObjectInstance;
354                         array.SetValue (ObjectRequired.ObjectInstance, _index);
355                 }
356         }
357
358         // MultiArrayFixupRecord
359         // Fixup for assigning a value to several positions of an array
360
361         internal class MultiArrayFixupRecord : BaseFixupRecord
362         {
363                 int[] _indices;
364
365                 public MultiArrayFixupRecord (ObjectRecord objectToBeFixed, int[] indices, ObjectRecord objectRequired): base (objectToBeFixed, objectRequired) {
366                         _indices = indices;
367                 }
368
369                 protected override void FixupImpl (ObjectManager manager) {
370                         ObjectToBeFixed.SetArrayValue (manager, ObjectRequired.ObjectInstance, _indices);
371                 }
372         }
373
374         // FixupRecord
375         // Fixup for assigning a value to a member of an object
376
377         internal class FixupRecord: BaseFixupRecord
378         {
379                 public MemberInfo _member;
380
381                 public FixupRecord (ObjectRecord objectToBeFixed, MemberInfo member, ObjectRecord objectRequired): base (objectToBeFixed, objectRequired) {
382                         _member = member;
383                 }
384
385                 protected override void FixupImpl (ObjectManager manager) {
386                         ObjectToBeFixed.SetMemberValue (manager, _member, ObjectRequired.ObjectInstance);
387                 }
388         }
389
390         // DelayedFixupRecord
391         // Fixup for assigning a value to a SerializationInfo of an object
392
393         internal class DelayedFixupRecord: BaseFixupRecord
394         {
395                 public string _memberName;
396
397                 public DelayedFixupRecord (ObjectRecord objectToBeFixed, string memberName, ObjectRecord objectRequired): base (objectToBeFixed, objectRequired) {
398                         _memberName = memberName;
399                 }
400
401                 protected override void FixupImpl (ObjectManager manager) {
402                         ObjectToBeFixed.SetMemberValue (manager, _memberName, ObjectRequired.ObjectInstance);
403                 }
404         }
405
406         // Object Record
407
408         internal enum ObjectRecordStatus: byte { Unregistered, ReferenceUnsolved, ReferenceSolvingDelayed, ReferenceSolved }
409
410         internal class ObjectRecord
411         {
412                 public ObjectRecordStatus Status = ObjectRecordStatus.Unregistered;
413                 public object OriginalObject;
414                 public object ObjectInstance;
415                 public long ObjectID;
416                 public SerializationInfo Info;
417                 public long IdOfContainingObj;
418                 public ISerializationSurrogate Surrogate;
419                 public ISurrogateSelector SurrogateSelector;
420                 public MemberInfo Member;
421                 public int[] ArrayIndex;
422                 public BaseFixupRecord FixupChainAsContainer;
423                 public BaseFixupRecord FixupChainAsRequired;
424                 public ObjectRecord Next;
425
426                 public void SetMemberValue (ObjectManager manager, MemberInfo member, object value)
427                 {
428                         if (member is FieldInfo)
429                                 ((FieldInfo)member).SetValue (ObjectInstance, value);
430                         else if (member is PropertyInfo)
431                                 ((PropertyInfo)member).SetValue (ObjectInstance, value, null);
432                         else throw new SerializationException ("Cannot perform fixup");
433
434                         if (Member != null)
435                         {
436                                 ObjectRecord containerRecord = manager.GetObjectRecord (IdOfContainingObj);
437                                 if (containerRecord.IsRegistered)
438                                         containerRecord.SetMemberValue (manager, Member, ObjectInstance);
439                         }
440                         else if (ArrayIndex != null)
441                         {
442                                 ObjectRecord containerRecord = manager.GetObjectRecord (IdOfContainingObj);
443                                 if (containerRecord.IsRegistered)
444                                         containerRecord.SetArrayValue (manager, ObjectInstance, ArrayIndex);
445                         }
446                 }
447                 public void SetArrayValue (ObjectManager manager, object value, int[] indices)
448                 {
449                         ((Array)ObjectInstance).SetValue (value, indices);
450                 }
451
452                 public void SetMemberValue (ObjectManager manager, string memberName, object value)
453                 {
454                         if (Info == null) throw new SerializationException ("Cannot perform fixup");
455                         Info.AddValue (memberName, value, value.GetType());
456                 }
457
458                 public bool IsInstanceReady
459                 {
460                         // Returns true if this object is ready to be assigned to a parent object.
461                         get
462                         {
463                                 if (!IsRegistered) return false;
464                                 if (IsUnsolvedObjectReference) return false;
465
466                                 // Embedded value objects cannot be assigned to their containers until fully completed
467                                 if (ObjectInstance.GetType ().IsValueType && (HasPendingFixups || Info != null))
468                                         return false;
469
470                                 return true;
471                         }
472                 }
473
474                 public bool IsUnsolvedObjectReference
475                 {
476                         get  {
477                                 return Status != ObjectRecordStatus.ReferenceSolved;
478                         }
479                 }
480
481                 public bool IsRegistered
482                 {
483                         get {
484                                 return Status != ObjectRecordStatus.Unregistered;
485                         }
486                 }
487
488                 public bool DoFixups (bool asContainer, ObjectManager manager, bool strict)
489                 {
490                         BaseFixupRecord prevFixup = null;
491                         BaseFixupRecord fixup = asContainer ? FixupChainAsContainer : FixupChainAsRequired;
492                         bool allFixed = true;
493
494                         while (fixup != null)
495                         {
496                                 if (fixup.DoFixup (manager, strict))
497                                 {
498                                         UnchainFixup (fixup, prevFixup, asContainer);
499                                         if (asContainer) fixup.ObjectRequired.RemoveFixup (fixup, false);
500                                         else fixup.ObjectToBeFixed.RemoveFixup (fixup, true);
501                                 }
502                                 else
503                                 {
504                                         prevFixup = fixup;
505                                         allFixed = false;
506                                 }
507
508                                 fixup = asContainer ? fixup.NextSameContainer : fixup.NextSameRequired;
509                         }
510                         return allFixed;
511                 }
512
513                 public void RemoveFixup (BaseFixupRecord fixupToRemove, bool asContainer)
514                 {
515                         BaseFixupRecord prevFixup = null;
516                         BaseFixupRecord fixup = asContainer ? FixupChainAsContainer : FixupChainAsRequired;
517                         while (fixup != null)
518                         {
519                                 if (fixup == fixupToRemove) 
520                                 {
521                                         UnchainFixup (fixup, prevFixup, asContainer);
522                                         return;
523                                 }
524                                 prevFixup = fixup;
525                                 fixup = asContainer ? fixup.NextSameContainer : fixup.NextSameRequired;
526                         }
527                 }
528
529                 private void UnchainFixup (BaseFixupRecord fixup, BaseFixupRecord prevFixup, bool asContainer)
530                 {
531                         if (prevFixup == null) {
532                                 if (asContainer) FixupChainAsContainer = fixup.NextSameContainer;
533                                 else FixupChainAsRequired = fixup.NextSameRequired;
534                         }
535                         else {
536                                 if (asContainer) prevFixup.NextSameContainer = fixup.NextSameContainer;
537                                 else prevFixup.NextSameRequired = fixup.NextSameRequired;
538                         }
539                 }
540
541                 public void ChainFixup (BaseFixupRecord fixup, bool asContainer)
542                 {
543                         if (asContainer) 
544                         {
545                                 fixup.NextSameContainer = FixupChainAsContainer;
546                                 FixupChainAsContainer = fixup;
547                         }
548                         else 
549                         {
550                                 fixup.NextSameRequired = FixupChainAsRequired;
551                                 FixupChainAsRequired = fixup;
552                         }
553                 }
554
555                 public bool LoadData (ObjectManager manager, ISurrogateSelector selector, StreamingContext context)
556                 {
557                         if (Info != null)
558                         {
559                                 if (Surrogate != null) {
560                                         object new_obj = Surrogate.SetObjectData (ObjectInstance, Info, context, SurrogateSelector);
561                                         if (new_obj != null)
562                                                 ObjectInstance = new_obj;
563                                         Status = ObjectRecordStatus.ReferenceSolved;
564                                 } else if (ObjectInstance is ISerializable) {
565                                         object[] pars = new object[] {Info, context};
566                                         ConstructorInfo con = ObjectInstance.GetType().GetConstructor (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof (SerializationInfo), typeof (StreamingContext) }, null );
567                                         if (con == null) throw new SerializationException ("The constructor to deserialize an object of type " + ObjectInstance.GetType().FullName + " was not found.");
568                                         con.Invoke (ObjectInstance, pars);
569                                 } else {
570                                         throw new SerializationException ("No surrogate selector was found for type " + ObjectInstance.GetType().FullName);
571                                 }
572
573                                 Info = null;
574                         }
575
576                         if (ObjectInstance is IObjectReference && Status != ObjectRecordStatus.ReferenceSolved)
577                         {
578                                 try {
579                                         ObjectInstance = ((IObjectReference)ObjectInstance).GetRealObject(context);
580                                         int n = 100;
581                                         while (ObjectInstance is IObjectReference && n > 0) {
582                                                 object ob = ((IObjectReference)ObjectInstance).GetRealObject (context);
583                                                 if (ob == ObjectInstance)
584                                                         break;
585                                                 ObjectInstance = ob;
586                                                 n--;
587                                         }
588                                         if (n == 0)
589                                                 throw new SerializationException ("The implementation of the IObjectReference interface returns too many nested references to other objects that implement IObjectReference.");
590                                         
591                                         Status = ObjectRecordStatus.ReferenceSolved;
592                                 }
593                                 catch (NullReferenceException) {
594                                         // Give a second chance
595                                         return false;
596                                 }
597                         }
598
599                         if (Member != null)
600                         {
601                                 // If this object is a value object embedded in another object, the parent
602                                 // object must be updated
603
604                                 ObjectRecord containerRecord = manager.GetObjectRecord (IdOfContainingObj);
605                                 containerRecord.SetMemberValue (manager, Member, ObjectInstance);
606                         }
607                         else if (ArrayIndex != null)
608                         {
609                                 ObjectRecord containerRecord = manager.GetObjectRecord (IdOfContainingObj);
610                                 containerRecord.SetArrayValue (manager, ObjectInstance, ArrayIndex);
611                         }
612
613                         return true;
614                 }
615
616                 public bool HasPendingFixups
617                 {
618                         get { return FixupChainAsContainer != null; }
619                 }
620         }
621 }