ObjectManager.cs 21 KB

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