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