b895c50f420f5e5ea3d8b758628863079da72472
[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
72                                 bool firstCycle = true;
73                                 bool lastCycle = false;
74                                 int unresolvedCount = 0;                // Unresolved objects found in the current cycle
75                                 int lastUnresolvedCount = 0;    // Unresolved objects before the current cycle
76
77                                 // Solve al pending fixups of all objects
78
79                                 ObjectRecord record = _objectRecordChain;
80                                 while (record != null)
81                                 {
82                                         // We ignore object references in the first cycle
83                                         bool ready = !(record.IsUnsolvedObjectReference && firstCycle);
84                                         if (ready) ready = record.DoFixups (true, this, true);
85                                         if (ready) ready = record.LoadData(this, _selector, _context);
86
87                                         ObjectRecord next;
88
89                                         if (ready)
90                                         {
91                                                 if (record.OriginalObject is IDeserializationCallback)
92                                                         _deserializedRecords.Add (record);
93
94                                                 SerializationCallbacks sc = SerializationCallbacks
95                                                         .GetSerializationCallbacks (record.OriginalObject.GetType ());
96                                                 if (sc.HasDeserializedCallbacks)
97                                                         _onDeserializedCallbackRecords.Add (record);
98                                                 next = record.Next;
99                                         }
100                                         else
101                                         {
102                                                 // There must be an unresolved IObjectReference instance.
103                                                 // Chain the record at the end so it is solved later
104
105                                                 if ((record.ObjectInstance is IObjectReference) && !firstCycle)
106                                                 {
107                                                         if (record.IsUnsolvedObjectReference && lastCycle)
108                                                                 // No more chances to resolve
109                                                                 throw new SerializationException ("The object with ID " + record.ObjectID + " could not be resolved");
110                                                         else {
111                                                                 unresolvedCount++;
112                                                         }
113                                                 }
114
115                                                 if (record != _lastObjectRecord) {
116                                                         next = record.Next;
117                                                         record.Next = null;
118                                                         _lastObjectRecord.Next = record;
119                                                         _lastObjectRecord = record;
120                                                 }
121                                                 else
122                                                         next = record;
123                                         }
124
125                                         if (record == last) {
126                                                 last = _lastObjectRecord;
127                                                 if (firstCycle)
128                                                         firstCycle = false;
129                                                 else {
130                                                         if (lastUnresolvedCount == unresolvedCount)
131                                                                 lastCycle = true;
132                                                 }
133                                                 lastUnresolvedCount = unresolvedCount;
134                                                 unresolvedCount = 0;
135                                         }
136                                         record = next;
137                                 }
138                         }
139                         finally
140                         {
141                                 _finalFixup = false;
142                         }
143                 }
144
145                 internal ObjectRecord GetObjectRecord (long objectID)
146                 {
147                         ObjectRecord rec = (ObjectRecord)_objectRecords[objectID];
148                         if (rec == null)
149                         {
150                                 if (_finalFixup) throw new SerializationException ("The object with Id " + objectID + " has not been registered");
151                                 rec = new ObjectRecord();
152                                 rec.ObjectID = objectID;
153                                 _objectRecords[objectID] = rec;
154                         }
155                         if (!rec.IsRegistered && _finalFixup) throw new SerializationException ("The object with Id " + objectID + " has not been registered");
156                         return rec;
157                 }
158
159                 public virtual object GetObject (long objectID)
160                 {
161                         if (objectID <= 0) throw new ArgumentOutOfRangeException("objectID","The objectID parameter is less than or equal to zero");
162                         ObjectRecord rec = (ObjectRecord)_objectRecords[objectID];
163                         if (rec == null || !rec.IsRegistered) return null;
164                         else return rec.ObjectInstance;
165                 }
166
167                 public virtual void RaiseDeserializationEvent ()
168                 {
169                         for (int i = _onDeserializedCallbackRecords.Count-1; i >= 0; i--)
170                         {
171                                 ObjectRecord record = (ObjectRecord) _onDeserializedCallbackRecords [i];
172                                 RaiseOnDeserializedEvent (record.OriginalObject);
173                         }
174                         for (int i = _deserializedRecords.Count-1; i >= 0; i--)
175                         {
176                                 ObjectRecord record = (ObjectRecord) _deserializedRecords [i];
177                                 IDeserializationCallback obj = record.OriginalObject as IDeserializationCallback;
178                                 if (obj != null) obj.OnDeserialization (this);
179                         }
180
181                 }
182
183                 public void RaiseOnDeserializingEvent (object obj)
184                 {
185                         SerializationCallbacks sc = SerializationCallbacks
186                                 .GetSerializationCallbacks (obj.GetType ());
187                         sc.RaiseOnDeserializing (obj, _context);
188                 }
189
190                 void RaiseOnDeserializedEvent (object obj)
191                 {
192                         SerializationCallbacks sc = SerializationCallbacks
193                                 .GetSerializationCallbacks (obj.GetType ());
194                         sc.RaiseOnDeserialized (obj, _context);
195                 }
196
197                 private void AddFixup (BaseFixupRecord record)
198                 {
199                         record.ObjectToBeFixed.ChainFixup (record, true);
200                         record.ObjectRequired.ChainFixup (record, false);
201                 }
202
203                 public virtual void RecordArrayElementFixup (long arrayToBeFixed, int index, long objectRequired)
204                 {
205                         if (arrayToBeFixed <= 0) throw new ArgumentOutOfRangeException("arrayToBeFixed","The arrayToBeFixed 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                         ArrayFixupRecord record = new ArrayFixupRecord(GetObjectRecord(arrayToBeFixed), index, GetObjectRecord(objectRequired));
208                         AddFixup (record);
209                 }
210
211                 public virtual void RecordArrayElementFixup (long arrayToBeFixed, int[] indices, long objectRequired)
212                 {
213                         if (arrayToBeFixed <= 0) throw new ArgumentOutOfRangeException("arrayToBeFixed","The arrayToBeFixed parameter is less than or equal to zero");
214                         if (objectRequired <= 0) throw new ArgumentOutOfRangeException("objectRequired","The objectRequired parameter is less than or equal to zero");
215                         if (indices == null) throw new ArgumentNullException("indices");
216                         MultiArrayFixupRecord record = new MultiArrayFixupRecord (GetObjectRecord(arrayToBeFixed), indices, GetObjectRecord(objectRequired));
217                         AddFixup (record);
218                 }
219
220                 public virtual void RecordDelayedFixup (long objectToBeFixed, string memberName, long objectRequired)
221                 {
222                         if (objectToBeFixed <= 0) throw new ArgumentOutOfRangeException("objectToBeFixed","The objectToBeFixed parameter is less than or equal to zero");
223                         if (objectRequired <= 0) throw new ArgumentOutOfRangeException("objectRequired","The objectRequired parameter is less than or equal to zero");
224                         if (memberName == null) throw new ArgumentNullException("memberName");
225                         DelayedFixupRecord record = new DelayedFixupRecord (GetObjectRecord(objectToBeFixed), memberName, GetObjectRecord(objectRequired));
226                         AddFixup (record);
227                 }
228
229                 public virtual void RecordFixup (long objectToBeFixed, MemberInfo member, long objectRequired)
230                 {
231                         if (objectToBeFixed <= 0) throw new ArgumentOutOfRangeException("objectToBeFixed","The objectToBeFixed parameter is less than or equal to zero");
232                         if (objectRequired <= 0) throw new ArgumentOutOfRangeException("objectRequired","The objectRequired parameter is less than or equal to zero");
233                         if (member == null) throw new ArgumentNullException("member");
234                         FixupRecord record = new FixupRecord (GetObjectRecord(objectToBeFixed), member, GetObjectRecord(objectRequired));
235                         AddFixup (record);
236                 }
237
238                 private void RegisterObjectInternal (object obj, ObjectRecord record)
239                 {
240                         if (obj == null) throw new ArgumentNullException("obj");
241
242                         if (record.IsRegistered)
243                         {
244                                 if (record.OriginalObject != obj) throw new SerializationException ("An object with Id " + record.ObjectID + " has already been registered");
245                                 else return;
246                         }
247
248                         record.ObjectInstance = obj;
249                         record.OriginalObject = obj;
250
251                         if (obj is IObjectReference) record.Status = ObjectRecordStatus.ReferenceUnsolved;
252                         else record.Status = ObjectRecordStatus.ReferenceSolved;
253
254                         if (_selector != null) {
255                                 record.Surrogate = _selector.GetSurrogate (
256                                         obj.GetType(), _context, out record.SurrogateSelector);
257                                 if (record.Surrogate != null)
258                                         record.Status = ObjectRecordStatus.ReferenceUnsolved;
259                         }
260
261                         record.DoFixups (true, this, false);
262                         record.DoFixups (false, this, false);
263                         _registeredObjectsCount++;
264
265                         // Adds the object to the chain of registered objects. This chain
266                         // is needed to be able to to perform the final fixups in the right order
267
268                         if (_objectRecordChain == null)
269                         {
270                                 _objectRecordChain = record;
271                                 _lastObjectRecord = record;
272                         }
273                         else 
274                         {
275                                 _lastObjectRecord.Next = record;
276                                 _lastObjectRecord = record;
277                         }
278                 }
279
280
281                 public virtual void RegisterObject (object obj, long objectID)
282                 {
283                         if (obj == null) throw new ArgumentNullException("obj", "The obj parameter is null.");
284                         if (objectID <= 0) throw new ArgumentOutOfRangeException("objectID","The objectID parameter is less than or equal to zero");
285                         RegisterObjectInternal (obj, GetObjectRecord (objectID));
286                 }
287
288                 public void RegisterObject (object obj, long objectID, SerializationInfo info)
289                 {
290                         if (obj == null) throw new ArgumentNullException("obj", "The obj parameter is null.");
291                         if (objectID <= 0) throw new ArgumentOutOfRangeException("objectID","The objectID parameter is less than or equal to zero");
292                         
293                         ObjectRecord record = GetObjectRecord (objectID);
294                         record.Info = info;
295                         RegisterObjectInternal (obj, record);
296                 }
297
298                 public void RegisterObject (object obj, long objectID, SerializationInfo info, long idOfContainingObj, MemberInfo member)
299                 {
300                         RegisterObject (obj, objectID, info, idOfContainingObj, member, null);
301                 }
302
303                 public void RegisterObject( object obj, long objectID, SerializationInfo info, long idOfContainingObj, MemberInfo member, int[] arrayIndex)
304                 {
305                         if (obj == null) throw new ArgumentNullException("obj", "The obj parameter is null.");
306                         if (objectID <= 0) throw new ArgumentOutOfRangeException("objectID","The objectID parameter is less than or equal to zero");
307
308                         ObjectRecord record = GetObjectRecord (objectID);
309                         record.Info = info;
310                         record.IdOfContainingObj = idOfContainingObj;
311                         record.Member = member;
312                         record.ArrayIndex = arrayIndex;
313                         RegisterObjectInternal (obj, record);
314                 }
315         }
316
317
318
319         // Fixup types. There is a fixup class for each fixup type.
320
321         // BaseFixupRecord
322         // Base class for all fixups
323
324         internal abstract class BaseFixupRecord
325         {
326                 public BaseFixupRecord(ObjectRecord objectToBeFixed, ObjectRecord objectRequired)
327                 {
328                         ObjectToBeFixed = objectToBeFixed;
329                         ObjectRequired = objectRequired;
330                 }
331
332                 public bool DoFixup (ObjectManager manager, bool strict)
333                 {
334                         if (ObjectToBeFixed.IsRegistered && ObjectRequired.IsInstanceReady)
335                         {
336                                 FixupImpl (manager);
337                                 return true;
338                         }
339                         else if (strict)
340                         {
341                                 if (!ObjectToBeFixed.IsRegistered) throw new SerializationException ("An object with ID " + ObjectToBeFixed.ObjectID + " was included in a fixup, but it has not been registered");
342                                 else if (!ObjectRequired.IsRegistered) throw new SerializationException ("An object with ID " + ObjectRequired.ObjectID + " was included in a fixup, but it has not been registered");
343                                 else return false;
344                         }
345                         else
346                                 return false;
347                 }
348
349                 protected abstract void FixupImpl (ObjectManager manager);
350
351                 internal protected ObjectRecord ObjectToBeFixed;
352                 internal protected ObjectRecord ObjectRequired;
353
354                 public BaseFixupRecord NextSameContainer;
355                 public BaseFixupRecord NextSameRequired;
356         }
357
358         // ArrayFixupRecord
359         // Fixup for assigning a value to one position of an array
360
361         internal class ArrayFixupRecord : BaseFixupRecord
362         {
363                 int _index;
364
365                 public ArrayFixupRecord (ObjectRecord objectToBeFixed, int index, ObjectRecord objectRequired): base (objectToBeFixed, objectRequired) {
366                         _index = index;
367                 }
368
369                 protected override void FixupImpl (ObjectManager manager) {
370                         Array array = (Array)ObjectToBeFixed.ObjectInstance;
371                         array.SetValue (ObjectRequired.ObjectInstance, _index);
372                 }
373         }
374
375         // MultiArrayFixupRecord
376         // Fixup for assigning a value to several positions of an array
377
378         internal class MultiArrayFixupRecord : BaseFixupRecord
379         {
380                 int[] _indices;
381
382                 public MultiArrayFixupRecord (ObjectRecord objectToBeFixed, int[] indices, ObjectRecord objectRequired): base (objectToBeFixed, objectRequired) {
383                         _indices = indices;
384                 }
385
386                 protected override void FixupImpl (ObjectManager manager) {
387                         ObjectToBeFixed.SetArrayValue (manager, ObjectRequired.ObjectInstance, _indices);
388                 }
389         }
390
391         // FixupRecord
392         // Fixup for assigning a value to a member of an object
393
394         internal class FixupRecord: BaseFixupRecord
395         {
396                 public MemberInfo _member;
397
398                 public FixupRecord (ObjectRecord objectToBeFixed, MemberInfo member, ObjectRecord objectRequired): base (objectToBeFixed, objectRequired) {
399                         _member = member;
400                 }
401
402                 protected override void FixupImpl (ObjectManager manager) {
403                         ObjectToBeFixed.SetMemberValue (manager, _member, ObjectRequired.ObjectInstance);
404                 }
405         }
406
407         // DelayedFixupRecord
408         // Fixup for assigning a value to a SerializationInfo of an object
409
410         internal class DelayedFixupRecord: BaseFixupRecord
411         {
412                 public string _memberName;
413
414                 public DelayedFixupRecord (ObjectRecord objectToBeFixed, string memberName, ObjectRecord objectRequired): base (objectToBeFixed, objectRequired) {
415                         _memberName = memberName;
416                 }
417
418                 protected override void FixupImpl (ObjectManager manager) {
419                         ObjectToBeFixed.SetMemberValue (manager, _memberName, ObjectRequired.ObjectInstance);
420                 }
421         }
422
423         // Object Record
424
425         internal enum ObjectRecordStatus: byte { Unregistered, ReferenceUnsolved, ReferenceSolved }
426
427         internal class ObjectRecord
428         {
429                 public ObjectRecordStatus Status = ObjectRecordStatus.Unregistered;
430                 public object OriginalObject;
431                 public object ObjectInstance;
432                 public long ObjectID;
433                 public SerializationInfo Info;
434                 public long IdOfContainingObj;
435                 public ISerializationSurrogate Surrogate;
436                 public ISurrogateSelector SurrogateSelector;
437                 public MemberInfo Member;
438                 public int[] ArrayIndex;
439                 public BaseFixupRecord FixupChainAsContainer;
440                 public BaseFixupRecord FixupChainAsRequired;
441                 public ObjectRecord Next;
442
443                 public void SetMemberValue (ObjectManager manager, MemberInfo member, object value)
444                 {
445                         if (member is FieldInfo)
446                                 ((FieldInfo)member).SetValue (ObjectInstance, value);
447                         else if (member is PropertyInfo)
448                                 ((PropertyInfo)member).SetValue (ObjectInstance, value, null);
449                         else throw new SerializationException ("Cannot perform fixup");
450
451                         if (Member != null)
452                         {
453                                 ObjectRecord containerRecord = manager.GetObjectRecord (IdOfContainingObj);
454                                 if (containerRecord.IsRegistered)
455                                         containerRecord.SetMemberValue (manager, Member, ObjectInstance);
456                         }
457                         else if (ArrayIndex != null)
458                         {
459                                 ObjectRecord containerRecord = manager.GetObjectRecord (IdOfContainingObj);
460                                 if (containerRecord.IsRegistered)
461                                         containerRecord.SetArrayValue (manager, ObjectInstance, ArrayIndex);
462                         }
463                 }
464                 public void SetArrayValue (ObjectManager manager, object value, int[] indices)
465                 {
466                         ((Array)ObjectInstance).SetValue (value, indices);
467                 }
468
469                 public void SetMemberValue (ObjectManager manager, string memberName, object value)
470                 {
471                         if (Info == null) throw new SerializationException ("Cannot perform fixup");
472                         Info.AddValue (memberName, value, value.GetType());
473                 }
474
475                 public bool IsInstanceReady
476                 {
477                         // Returns true if this object is ready to be assigned to a parent object.
478                         get
479                         {
480                                 if (!IsRegistered) return false;
481                                 if (IsUnsolvedObjectReference) return false;
482
483                                 // Embedded value objects cannot be assigned to their containers until fully completed
484                                 if (ObjectInstance.GetType ().IsValueType && (HasPendingFixups || Info != null))
485                                         return false;
486
487                                 return true;
488                         }
489                 }
490
491                 public bool IsUnsolvedObjectReference
492                 {
493                         get  {
494                                 return Status != ObjectRecordStatus.ReferenceSolved;
495                         }
496                 }
497
498                 public bool IsRegistered
499                 {
500                         get {
501                                 return Status != ObjectRecordStatus.Unregistered;
502                         }
503                 }
504
505                 public bool DoFixups (bool asContainer, ObjectManager manager, bool strict)
506                 {
507                         BaseFixupRecord prevFixup = null;
508                         BaseFixupRecord fixup = asContainer ? FixupChainAsContainer : FixupChainAsRequired;
509                         bool allFixed = true;
510
511                         while (fixup != null)
512                         {
513                                 if (fixup.DoFixup (manager, strict))
514                                 {
515                                         UnchainFixup (fixup, prevFixup, asContainer);
516                                         if (asContainer) fixup.ObjectRequired.RemoveFixup (fixup, false);
517                                         else fixup.ObjectToBeFixed.RemoveFixup (fixup, true);
518                                 }
519                                 else
520                                 {
521                                         prevFixup = fixup;
522                                         allFixed = false;
523                                 }
524
525                                 fixup = asContainer ? fixup.NextSameContainer : fixup.NextSameRequired;
526                         }
527                         return allFixed;
528                 }
529
530                 public void RemoveFixup (BaseFixupRecord fixupToRemove, bool asContainer)
531                 {
532                         BaseFixupRecord prevFixup = null;
533                         BaseFixupRecord fixup = asContainer ? FixupChainAsContainer : FixupChainAsRequired;
534                         while (fixup != null)
535                         {
536                                 if (fixup == fixupToRemove) 
537                                 {
538                                         UnchainFixup (fixup, prevFixup, asContainer);
539                                         return;
540                                 }
541                                 prevFixup = fixup;
542                                 fixup = asContainer ? fixup.NextSameContainer : fixup.NextSameRequired;
543                         }
544                 }
545
546                 private void UnchainFixup (BaseFixupRecord fixup, BaseFixupRecord prevFixup, bool asContainer)
547                 {
548                         if (prevFixup == null) {
549                                 if (asContainer) FixupChainAsContainer = fixup.NextSameContainer;
550                                 else FixupChainAsRequired = fixup.NextSameRequired;
551                         }
552                         else {
553                                 if (asContainer) prevFixup.NextSameContainer = fixup.NextSameContainer;
554                                 else prevFixup.NextSameRequired = fixup.NextSameRequired;
555                         }
556                 }
557
558                 public void ChainFixup (BaseFixupRecord fixup, bool asContainer)
559                 {
560                         if (asContainer) 
561                         {
562                                 fixup.NextSameContainer = FixupChainAsContainer;
563                                 FixupChainAsContainer = fixup;
564                         }
565                         else 
566                         {
567                                 fixup.NextSameRequired = FixupChainAsRequired;
568                                 FixupChainAsRequired = fixup;
569                         }
570                 }
571
572                 public bool LoadData (ObjectManager manager, ISurrogateSelector selector, StreamingContext context)
573                 {
574                         if (Info != null)
575                         {
576                                 if (Surrogate != null) {
577                                         object new_obj = Surrogate.SetObjectData (ObjectInstance, Info, context, SurrogateSelector);
578                                         if (new_obj != null)
579                                                 ObjectInstance = new_obj;
580                                         Status = ObjectRecordStatus.ReferenceSolved;
581                                 } else if (ObjectInstance is ISerializable) {
582                                         object[] pars = new object[] {Info, context};
583                                         ConstructorInfo con = ObjectInstance.GetType().GetConstructor (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof (SerializationInfo), typeof (StreamingContext) }, null );
584                                         if (con == null) throw new SerializationException ("The constructor to deserialize an object of type " + ObjectInstance.GetType().FullName + " was not found.");
585                                         con.Invoke (ObjectInstance, pars);
586                                 } else {
587                                         throw new SerializationException ("No surrogate selector was found for type " + ObjectInstance.GetType().FullName);
588                                 }
589
590                                 Info = null;
591                         }
592
593                         if (ObjectInstance is IObjectReference && Status != ObjectRecordStatus.ReferenceSolved)
594                         {
595                                 try {
596                                         ObjectInstance = ((IObjectReference)ObjectInstance).GetRealObject(context);
597                                         int n = 100;
598                                         while (ObjectInstance is IObjectReference && n > 0) {
599                                                 object ob = ((IObjectReference)ObjectInstance).GetRealObject (context);
600                                                 if (ob == ObjectInstance)
601                                                         break;
602                                                 ObjectInstance = ob;
603                                                 n--;
604                                         }
605                                         if (n == 0)
606                                                 throw new SerializationException ("The implementation of the IObjectReference interface returns too many nested references to other objects that implement IObjectReference.");
607                                         
608                                         Status = ObjectRecordStatus.ReferenceSolved;
609                                 }
610                                 catch (NullReferenceException) {
611                                         // Give a second chance
612                                         return false;
613                                 }
614                         }
615
616                         if (Member != null)
617                         {
618                                 // If this object is a value object embedded in another object, the parent
619                                 // object must be updated
620
621                                 ObjectRecord containerRecord = manager.GetObjectRecord (IdOfContainingObj);
622                                 containerRecord.SetMemberValue (manager, Member, ObjectInstance);
623                         }
624                         else if (ArrayIndex != null)
625                         {
626                                 ObjectRecord containerRecord = manager.GetObjectRecord (IdOfContainingObj);
627                                 containerRecord.SetArrayValue (manager, ObjectInstance, ArrayIndex);
628                         }
629
630                         return true;
631                 }
632
633                 public bool HasPendingFixups
634                 {
635                         get { return FixupChainAsContainer != null; }
636                 }
637         }
638 }