BsonDocument.cs 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334
  1. /* Copyright 2010-2014 MongoDB Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. using System;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.IO;
  19. using System.Linq;
  20. using MongoDB.Bson.IO;
  21. using MongoDB.Bson.Serialization;
  22. using MongoDB.Bson.Serialization.Serializers;
  23. using MongoDB.Shared;
  24. namespace MongoDB.Bson
  25. {
  26. /// <summary>
  27. /// Represents a BSON document.
  28. /// </summary>
  29. [Serializable]
  30. public class BsonDocument : BsonValue, IBsonSerializable, IComparable<BsonDocument>, IConvertibleToBsonDocument, IEnumerable<BsonElement>, IEquatable<BsonDocument>
  31. {
  32. // private fields
  33. // use a list and a dictionary because we want to preserve the order in which the elements were added
  34. // if duplicate names are present only the first one will be in the dictionary (the others can only be accessed by index)
  35. private List<BsonElement> _elements = new List<BsonElement>();
  36. private Dictionary<string, int> _indexes = new Dictionary<string, int>(); // maps names to indexes into elements list
  37. private bool _allowDuplicateNames;
  38. // constructors
  39. /// <summary>
  40. /// Initializes a new instance of the BsonDocument class.
  41. /// </summary>
  42. public BsonDocument()
  43. : base(BsonType.Document)
  44. {
  45. }
  46. /// <summary>
  47. /// Initializes a new instance of the BsonDocument class specifying whether duplicate element names are allowed
  48. /// (allowing duplicate element names is not recommended).
  49. /// </summary>
  50. /// <param name="allowDuplicateNames">Whether duplicate element names are allowed.</param>
  51. public BsonDocument(bool allowDuplicateNames)
  52. : base(BsonType.Document)
  53. {
  54. _allowDuplicateNames = allowDuplicateNames;
  55. }
  56. /// <summary>
  57. /// Initializes a new instance of the BsonDocument class and adds one element.
  58. /// </summary>
  59. /// <param name="element">An element to add to the document.</param>
  60. public BsonDocument(BsonElement element)
  61. : base(BsonType.Document)
  62. {
  63. Add(element);
  64. }
  65. /// <summary>
  66. /// Initializes a new instance of the BsonDocument class and adds new elements from a dictionary of key/value pairs.
  67. /// </summary>
  68. /// <param name="dictionary">A dictionary to initialize the document from.</param>
  69. public BsonDocument(Dictionary<string, object> dictionary)
  70. : base(BsonType.Document)
  71. {
  72. AddRange(dictionary);
  73. }
  74. /// <summary>
  75. /// Initializes a new instance of the BsonDocument class and adds new elements from a dictionary of key/value pairs.
  76. /// </summary>
  77. /// <param name="dictionary">A dictionary to initialize the document from.</param>
  78. /// <param name="keys">A list of keys to select values from the dictionary.</param>
  79. [Obsolete("Use BsonDocument(IEnumerable<BsonElement> elements) instead.")]
  80. public BsonDocument(Dictionary<string, object> dictionary, IEnumerable<string> keys)
  81. : base(BsonType.Document)
  82. {
  83. Add(dictionary, keys);
  84. }
  85. /// <summary>
  86. /// Initializes a new instance of the BsonDocument class and adds new elements from a dictionary of key/value pairs.
  87. /// </summary>
  88. /// <param name="dictionary">A dictionary to initialize the document from.</param>
  89. public BsonDocument(IEnumerable<KeyValuePair<string, object>> dictionary)
  90. : base(BsonType.Document)
  91. {
  92. AddRange(dictionary);
  93. }
  94. /// <summary>
  95. /// Initializes a new instance of the BsonDocument class and adds new elements from a dictionary of key/value pairs.
  96. /// </summary>
  97. /// <param name="dictionary">A dictionary to initialize the document from.</param>
  98. /// <param name="keys">A list of keys to select values from the dictionary.</param>
  99. [Obsolete("Use BsonDocument(IEnumerable<BsonElement> elements) instead.")]
  100. public BsonDocument(IDictionary<string, object> dictionary, IEnumerable<string> keys)
  101. : base(BsonType.Document)
  102. {
  103. Add(dictionary, keys);
  104. }
  105. /// <summary>
  106. /// Initializes a new instance of the BsonDocument class and adds new elements from a dictionary of key/value pairs.
  107. /// </summary>
  108. /// <param name="dictionary">A dictionary to initialize the document from.</param>
  109. public BsonDocument(IDictionary dictionary)
  110. : base(BsonType.Document)
  111. {
  112. AddRange(dictionary);
  113. }
  114. /// <summary>
  115. /// Initializes a new instance of the BsonDocument class and adds new elements from a dictionary of key/value pairs.
  116. /// </summary>
  117. /// <param name="dictionary">A dictionary to initialize the document from.</param>
  118. /// <param name="keys">A list of keys to select values from the dictionary.</param>
  119. [Obsolete("Use BsonDocument(IEnumerable<BsonElement> elements) instead.")]
  120. public BsonDocument(IDictionary dictionary, IEnumerable keys)
  121. : base(BsonType.Document)
  122. {
  123. Add(dictionary, keys);
  124. }
  125. /// <summary>
  126. /// Initializes a new instance of the BsonDocument class and adds new elements from a list of elements.
  127. /// </summary>
  128. /// <param name="elements">A list of elements to add to the document.</param>
  129. public BsonDocument(IEnumerable<BsonElement> elements)
  130. : base(BsonType.Document)
  131. {
  132. AddRange(elements);
  133. }
  134. /// <summary>
  135. /// Initializes a new instance of the BsonDocument class and adds one or more elements.
  136. /// </summary>
  137. /// <param name="elements">One or more elements to add to the document.</param>
  138. [Obsolete("Use BsonDocument(IEnumerable<BsonElement> elements) instead.")]
  139. public BsonDocument(params BsonElement[] elements)
  140. : base(BsonType.Document)
  141. {
  142. Add(elements);
  143. }
  144. /// <summary>
  145. /// Initializes a new instance of the BsonDocument class and creates and adds a new element.
  146. /// </summary>
  147. /// <param name="name">The name of the element to add to the document.</param>
  148. /// <param name="value">The value of the element to add to the document.</param>
  149. public BsonDocument(string name, BsonValue value)
  150. : base(BsonType.Document)
  151. {
  152. Add(name, value);
  153. }
  154. // public operators
  155. /// <summary>
  156. /// Compares two BsonDocument values.
  157. /// </summary>
  158. /// <param name="lhs">The first BsonDocument.</param>
  159. /// <param name="rhs">The other BsonDocument.</param>
  160. /// <returns>True if the two BsonDocument values are not equal according to ==.</returns>
  161. public static bool operator !=(BsonDocument lhs, BsonDocument rhs)
  162. {
  163. return !(lhs == rhs);
  164. }
  165. /// <summary>
  166. /// Compares two BsonDocument values.
  167. /// </summary>
  168. /// <param name="lhs">The first BsonDocument.</param>
  169. /// <param name="rhs">The other BsonDocument.</param>
  170. /// <returns>True if the two BsonDocument values are equal according to ==.</returns>
  171. public static bool operator ==(BsonDocument lhs, BsonDocument rhs)
  172. {
  173. return object.Equals(lhs, rhs); // handles lhs == null correctly
  174. }
  175. // public properties
  176. /// <summary>
  177. /// Gets or sets whether to allow duplicate names (allowing duplicate names is not recommended).
  178. /// </summary>
  179. public bool AllowDuplicateNames
  180. {
  181. get { return _allowDuplicateNames; }
  182. set { _allowDuplicateNames = value; }
  183. }
  184. // ElementCount could be greater than the number of Names if allowDuplicateNames is true
  185. /// <summary>
  186. /// Gets the number of elements.
  187. /// </summary>
  188. public virtual int ElementCount
  189. {
  190. get { return _elements.Count; }
  191. }
  192. /// <summary>
  193. /// Gets the elements.
  194. /// </summary>
  195. public virtual IEnumerable<BsonElement> Elements
  196. {
  197. get { return _elements; }
  198. }
  199. /// <summary>
  200. /// Gets the element names.
  201. /// </summary>
  202. public virtual IEnumerable<string> Names
  203. {
  204. get { return _elements.Select(e => e.Name); }
  205. }
  206. /// <summary>
  207. /// Gets the raw values (see BsonValue.RawValue).
  208. /// </summary>
  209. [Obsolete("Use Values instead.")]
  210. public virtual IEnumerable<object> RawValues
  211. {
  212. get { return _elements.Select(e => e.Value.RawValue); }
  213. }
  214. /// <summary>
  215. /// Gets the values.
  216. /// </summary>
  217. public virtual IEnumerable<BsonValue> Values
  218. {
  219. get { return _elements.Select(e => e.Value); }
  220. }
  221. // public indexers
  222. // note: the return type of the indexers is BsonValue and NOT BsonElement so that we can write code like:
  223. // BsonDocument car;
  224. // car["color"] = "red"; // changes value of existing element or adds new element
  225. // note: we are using implicit conversion from string to BsonValue
  226. // to convert the returned BsonValue to a .NET type you have two approaches (explicit cast or As method):
  227. // string color = (string) car["color"]; // throws exception if value is not a string (returns null if not found)
  228. // string color = car["color"].AsString; // throws exception if value is not a string (results in a NullReferenceException if not found)
  229. // string color = car["color", "none"].AsString; // throws exception if value is not a string (default to "none" if not found)
  230. // the second approach offers a more fluent interface (with fewer parenthesis!)
  231. // string name = car["brand"].AsBsonSymbol.Name;
  232. // string name = ((BsonSymbol) car["brand"]).Name; // the extra parenthesis are required and harder to read
  233. // there are also some conversion methods (and note that ToBoolean uses the JavaScript definition of truthiness)
  234. // bool ok = result["ok"].ToBoolean(); // works whether ok is false, true, 0, 0.0, 1, 1.0, "", "xyz", BsonNull.Value, etc...
  235. // bool ok = result["ok", false].ToBoolean(); // defaults to false if ok element is not found
  236. // int n = result["n"].ToInt32(); // works whether n is Int32, Int64, Double or String (if it can be parsed)
  237. // long n = result["n"].ToInt64(); // works whether n is Int32, Int64, Double or String (if it can be parsed)
  238. // double d = result["n"].ToDouble(); // works whether d is Int32, Int64, Double or String (if it can be parsed)
  239. // to work in terms of BsonElements use Add, GetElement and SetElement
  240. // car.Add(new BsonElement("color", "red")); // might throw exception if allowDuplicateNames is false
  241. // car.SetElement(new BsonElement("color", "red")); // replaces existing element or adds new element
  242. // BsonElement colorElement = car.GetElement("color"); // returns null if element "color" is not found
  243. /// <summary>
  244. /// Gets or sets a value by position.
  245. /// </summary>
  246. /// <param name="index">The position.</param>
  247. /// <returns>The value.</returns>
  248. public override BsonValue this[int index]
  249. {
  250. get { return _elements[index].Value; }
  251. set {
  252. if (value == null)
  253. {
  254. throw new ArgumentNullException("value");
  255. }
  256. _elements[index].Value = value;
  257. }
  258. }
  259. /// <summary>
  260. /// Gets the value of an element or a default value if the element is not found.
  261. /// </summary>
  262. /// <param name="name">The name of the element.</param>
  263. /// <param name="defaultValue">The default value to return if the element is not found.</param>
  264. /// <returns>Teh value of the element or a default value if the element is not found.</returns>
  265. [Obsolete("Use GetValue(string name, BsonValue defaultValue) instead.")]
  266. public virtual BsonValue this[string name, BsonValue defaultValue]
  267. {
  268. get { return GetValue(name, defaultValue); }
  269. }
  270. /// <summary>
  271. /// Gets or sets a value by name.
  272. /// </summary>
  273. /// <param name="name">The name.</param>
  274. /// <returns>The value.</returns>
  275. public override BsonValue this[string name]
  276. {
  277. get
  278. {
  279. if (name == null)
  280. {
  281. throw new ArgumentNullException("name");
  282. }
  283. int index;
  284. if (_indexes.TryGetValue(name, out index))
  285. {
  286. return _elements[index].Value;
  287. }
  288. else
  289. {
  290. string message = string.Format("Element '{0}' not found.", name);
  291. throw new KeyNotFoundException(message);
  292. }
  293. }
  294. set
  295. {
  296. if (name == null)
  297. {
  298. throw new ArgumentNullException("name");
  299. }
  300. if (value == null)
  301. {
  302. throw new ArgumentNullException("value");
  303. }
  304. int index;
  305. if (_indexes.TryGetValue(name, out index))
  306. {
  307. _elements[index].Value = value;
  308. }
  309. else
  310. {
  311. Add(new BsonElement(name, value));
  312. }
  313. }
  314. }
  315. // public static methods
  316. /// <summary>
  317. /// Creates a new BsonDocument by mapping an object to a BsonDocument.
  318. /// </summary>
  319. /// <param name="value">The object to be mapped to a BsonDocument.</param>
  320. /// <returns>A BsonDocument.</returns>
  321. public new static BsonDocument Create(object value)
  322. {
  323. if (value != null)
  324. {
  325. return (BsonDocument)BsonTypeMapper.MapToBsonValue(value, BsonType.Document);
  326. }
  327. else
  328. {
  329. return null;
  330. }
  331. }
  332. /// <summary>
  333. /// Parses a JSON string and returns a BsonDocument.
  334. /// </summary>
  335. /// <param name="json">The JSON string.</param>
  336. /// <returns>A BsonDocument.</returns>
  337. public static BsonDocument Parse(string json)
  338. {
  339. using (var bsonReader = BsonReader.Create(json))
  340. {
  341. return (BsonDocument)BsonDocumentSerializer.Instance.Deserialize(bsonReader, typeof(BsonDocument), null);
  342. }
  343. }
  344. /// <summary>
  345. /// Reads a BsonDocument from a BsonBuffer.
  346. /// </summary>
  347. /// <param name="buffer">The BsonBuffer.</param>
  348. /// <returns>A BsonDocument.</returns>
  349. [Obsolete("Use BsonSerializer.Deserialize<BsonDocument> instead.")]
  350. public static BsonDocument ReadFrom(BsonBuffer buffer)
  351. {
  352. using (BsonReader bsonReader = BsonReader.Create(buffer))
  353. {
  354. return BsonSerializer.Deserialize<BsonDocument>(bsonReader);
  355. }
  356. }
  357. /// <summary>
  358. /// Reads a BsonDocument from a BsonReader.
  359. /// </summary>
  360. /// <param name="bsonReader">The BsonReader.</param>
  361. /// <returns>A BsonDocument.</returns>
  362. [Obsolete("Use BsonSerializer.Deserialize<BsonDocument> instead.")]
  363. public static new BsonDocument ReadFrom(BsonReader bsonReader)
  364. {
  365. return BsonSerializer.Deserialize<BsonDocument>(bsonReader);
  366. }
  367. /// <summary>
  368. /// Reads a BsonDocument from a byte array.
  369. /// </summary>
  370. /// <param name="bytes">The byte array.</param>
  371. /// <returns>A BsonDocument.</returns>
  372. [Obsolete("Use BsonSerializer.Deserialize<BsonDocument> instead.")]
  373. public static BsonDocument ReadFrom(byte[] bytes)
  374. {
  375. return BsonSerializer.Deserialize<BsonDocument>(bytes);
  376. }
  377. /// <summary>
  378. /// Reads a BsonDocument from a stream.
  379. /// </summary>
  380. /// <param name="stream">The stream.</param>
  381. /// <returns>A BsonDocument.</returns>
  382. [Obsolete("Use BsonSerializer.Deserialize<BsonDocument> instead.")]
  383. public static BsonDocument ReadFrom(Stream stream)
  384. {
  385. return BsonSerializer.Deserialize<BsonDocument>(stream);
  386. }
  387. /// <summary>
  388. /// Reads a BsonDocument from a file.
  389. /// </summary>
  390. /// <param name="filename">The name of the file.</param>
  391. /// <returns>A BsonDocument.</returns>
  392. [Obsolete("Use BsonSerializer.Deserialize<BsonDocument> instead.")]
  393. public static BsonDocument ReadFrom(string filename)
  394. {
  395. using (var stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.None))
  396. {
  397. return BsonSerializer.Deserialize<BsonDocument>(stream);
  398. }
  399. }
  400. // public methods
  401. /// <summary>
  402. /// Adds an element to the document.
  403. /// </summary>
  404. /// <param name="element">The element to add.</param>
  405. /// <returns>The document (so method calls can be chained).</returns>
  406. public virtual BsonDocument Add(BsonElement element)
  407. {
  408. if (element != null)
  409. {
  410. bool found;
  411. int index;
  412. if ((found = _indexes.TryGetValue(element.Name, out index)) && !_allowDuplicateNames)
  413. {
  414. var message = string.Format("Duplicate element name '{0}'.", element.Name);
  415. throw new InvalidOperationException(message);
  416. }
  417. else
  418. {
  419. _elements.Add(element);
  420. if (!found)
  421. {
  422. _indexes.Add(element.Name, _elements.Count - 1); // index of the newly added element
  423. }
  424. }
  425. }
  426. return this;
  427. }
  428. /// <summary>
  429. /// Adds elements to the document from a dictionary of key/value pairs.
  430. /// </summary>
  431. /// <param name="dictionary">The dictionary.</param>
  432. /// <returns>The document (so method calls can be chained).</returns>
  433. [Obsolete("Use AddRange instead.")]
  434. public virtual BsonDocument Add(Dictionary<string, object> dictionary)
  435. {
  436. return AddRange(dictionary);
  437. }
  438. /// <summary>
  439. /// Adds elements to the document from a dictionary of key/value pairs.
  440. /// </summary>
  441. /// <param name="dictionary">The dictionary.</param>
  442. /// <param name="keys">Which keys of the hash table to add.</param>
  443. /// <returns>The document (so method calls can be chained).</returns>
  444. [Obsolete("Use AddRange(IEnumerable<BsonElement> elements) instead.")]
  445. public virtual BsonDocument Add(Dictionary<string, object> dictionary, IEnumerable<string> keys)
  446. {
  447. return Add((IDictionary<string, object>)dictionary, keys);
  448. }
  449. /// <summary>
  450. /// Adds elements to the document from a dictionary of key/value pairs.
  451. /// </summary>
  452. /// <param name="dictionary">The dictionary.</param>
  453. /// <returns>The document (so method calls can be chained).</returns>
  454. [Obsolete("Use AddRange instead.")]
  455. public virtual BsonDocument Add(IDictionary<string, object> dictionary)
  456. {
  457. return AddRange(dictionary);
  458. }
  459. /// <summary>
  460. /// Adds elements to the document from a dictionary of key/value pairs.
  461. /// </summary>
  462. /// <param name="dictionary">The dictionary.</param>
  463. /// <param name="keys">Which keys of the hash table to add.</param>
  464. /// <returns>The document (so method calls can be chained).</returns>
  465. [Obsolete("Use AddRange(IEnumerable<BsonElement> elements) instead.")]
  466. public virtual BsonDocument Add(IDictionary<string, object> dictionary, IEnumerable<string> keys)
  467. {
  468. if (keys == null)
  469. {
  470. throw new ArgumentNullException("keys");
  471. }
  472. if (dictionary != null)
  473. {
  474. foreach (var key in keys)
  475. {
  476. Add(key, BsonTypeMapper.MapToBsonValue(dictionary[key]));
  477. }
  478. }
  479. return this;
  480. }
  481. /// <summary>
  482. /// Adds elements to the document from a dictionary of key/value pairs.
  483. /// </summary>
  484. /// <param name="dictionary">The dictionary.</param>
  485. /// <returns>The document (so method calls can be chained).</returns>
  486. [Obsolete("Use AddRange instead.")]
  487. public virtual BsonDocument Add(IDictionary dictionary)
  488. {
  489. return AddRange(dictionary);
  490. }
  491. /// <summary>
  492. /// Adds elements to the document from a dictionary of key/value pairs.
  493. /// </summary>
  494. /// <param name="dictionary">The dictionary.</param>
  495. /// <param name="keys">Which keys of the hash table to add.</param>
  496. /// <returns>The document (so method calls can be chained).</returns>
  497. [Obsolete("Use AddRange(IEnumerable<BsonElement> elements) instead.")]
  498. public virtual BsonDocument Add(IDictionary dictionary, IEnumerable keys)
  499. {
  500. if (keys == null)
  501. {
  502. throw new ArgumentNullException("keys");
  503. }
  504. if (dictionary != null)
  505. {
  506. foreach (var key in keys)
  507. {
  508. if (key.GetType() != typeof(string))
  509. {
  510. throw new ArgumentOutOfRangeException("keys", "A key passed to BsonDocument.Add is not a string.");
  511. }
  512. Add((string)key, BsonTypeMapper.MapToBsonValue(dictionary[key]));
  513. }
  514. }
  515. return this;
  516. }
  517. /// <summary>
  518. /// Adds a list of elements to the document.
  519. /// </summary>
  520. /// <param name="elements">The list of elements.</param>
  521. /// <returns>The document (so method calls can be chained).</returns>
  522. [Obsolete("Use AddRange instead.")]
  523. public virtual BsonDocument Add(IEnumerable<BsonElement> elements)
  524. {
  525. return AddRange(elements);
  526. }
  527. /// <summary>
  528. /// Adds a list of elements to the document.
  529. /// </summary>
  530. /// <param name="elements">The list of elements.</param>
  531. /// <returns>The document (so method calls can be chained).</returns>
  532. [Obsolete("Use AddRange(IEnumerable<BsonElement> elements) instead.")]
  533. public virtual BsonDocument Add(params BsonElement[] elements)
  534. {
  535. return AddRange((IEnumerable<BsonElement>)elements);
  536. }
  537. /// <summary>
  538. /// Creates and adds an element to the document.
  539. /// </summary>
  540. /// <param name="name">The name of the element.</param>
  541. /// <param name="value">The value of the element.</param>
  542. /// <returns>The document (so method calls can be chained).</returns>
  543. public virtual BsonDocument Add(string name, BsonValue value)
  544. {
  545. if (name == null)
  546. {
  547. throw new ArgumentNullException("name");
  548. }
  549. if (value != null)
  550. {
  551. Add(new BsonElement(name, value));
  552. }
  553. return this;
  554. }
  555. /// <summary>
  556. /// Creates and adds an element to the document, but only if the condition is true.
  557. /// </summary>
  558. /// <param name="name">The name of the element.</param>
  559. /// <param name="value">The value of the element.</param>
  560. /// <param name="condition">Whether to add the element to the document.</param>
  561. /// <returns>The document (so method calls can be chained).</returns>
  562. public virtual BsonDocument Add(string name, BsonValue value, bool condition)
  563. {
  564. if (name == null)
  565. {
  566. throw new ArgumentNullException("name");
  567. }
  568. if (value != null && condition)
  569. {
  570. Add(new BsonElement(name, value));
  571. }
  572. return this;
  573. }
  574. /// <summary>
  575. /// Creates and adds an element to the document, but only if the condition is true.
  576. /// If the condition is false the value factory is not called at all.
  577. /// </summary>
  578. /// <param name="name">The name of the element.</param>
  579. /// <param name="valueFactory">A delegate called to compute the value of the element if condition is true.</param>
  580. /// <param name="condition">Whether to add the element to the document.</param>
  581. /// <returns>The document (so method calls can be chained).</returns>
  582. public virtual BsonDocument Add(string name, Func<BsonValue> valueFactory, bool condition)
  583. {
  584. if (name == null)
  585. {
  586. throw new ArgumentNullException("name");
  587. }
  588. if (valueFactory == null)
  589. {
  590. throw new ArgumentNullException("valueFactory");
  591. }
  592. if (condition)
  593. {
  594. Add(new BsonElement(name, valueFactory()));
  595. }
  596. return this;
  597. }
  598. /// <summary>
  599. /// Adds elements to the document from a dictionary of key/value pairs.
  600. /// </summary>
  601. /// <param name="dictionary">The dictionary.</param>
  602. /// <returns>The document (so method calls can be chained).</returns>
  603. public virtual BsonDocument AddRange(Dictionary<string, object> dictionary)
  604. {
  605. return AddRange((IEnumerable<KeyValuePair<string, object>>)dictionary);
  606. }
  607. /// <summary>
  608. /// Adds elements to the document from a dictionary of key/value pairs.
  609. /// </summary>
  610. /// <param name="dictionary">The dictionary.</param>
  611. /// <returns>The document (so method calls can be chained).</returns>
  612. public virtual BsonDocument AddRange(IDictionary dictionary)
  613. {
  614. if (dictionary != null)
  615. {
  616. foreach (DictionaryEntry entry in dictionary)
  617. {
  618. if (entry.Key.GetType() != typeof(string))
  619. {
  620. throw new ArgumentOutOfRangeException("dictionary", "One or more keys in the dictionary passed to BsonDocument.AddRange is not a string.");
  621. }
  622. Add((string)entry.Key, BsonTypeMapper.MapToBsonValue(entry.Value));
  623. }
  624. }
  625. return this;
  626. }
  627. /// <summary>
  628. /// Adds a list of elements to the document.
  629. /// </summary>
  630. /// <param name="elements">The list of elements.</param>
  631. /// <returns>The document (so method calls can be chained).</returns>
  632. public virtual BsonDocument AddRange(IEnumerable<BsonElement> elements)
  633. {
  634. if (elements != null)
  635. {
  636. foreach (var element in elements)
  637. {
  638. Add(element);
  639. }
  640. }
  641. return this;
  642. }
  643. /// <summary>
  644. /// Adds elements to the document from a dictionary of key/value pairs.
  645. /// </summary>
  646. /// <param name="dictionary">The dictionary.</param>
  647. /// <returns>The document (so method calls can be chained).</returns>
  648. public virtual BsonDocument AddRange(IEnumerable<KeyValuePair<string, object>> dictionary)
  649. {
  650. if (dictionary != null)
  651. {
  652. foreach (var entry in dictionary)
  653. {
  654. Add(entry.Key, BsonTypeMapper.MapToBsonValue(entry.Value));
  655. }
  656. }
  657. return this;
  658. }
  659. /// <summary>
  660. /// Clears the document (removes all elements).
  661. /// </summary>
  662. public virtual void Clear()
  663. {
  664. _elements.Clear();
  665. _indexes.Clear();
  666. }
  667. /// <summary>
  668. /// Creates a shallow clone of the document (see also DeepClone).
  669. /// </summary>
  670. /// <returns>A shallow clone of the document.</returns>
  671. public override BsonValue Clone()
  672. {
  673. BsonDocument clone = new BsonDocument();
  674. foreach (BsonElement element in _elements)
  675. {
  676. clone.Add(element.Clone());
  677. }
  678. return clone;
  679. }
  680. /// <summary>
  681. /// Compares this document to another document.
  682. /// </summary>
  683. /// <param name="rhs">The other document.</param>
  684. /// <returns>A 32-bit signed integer that indicates whether this document is less than, equal to, or greather than the other.</returns>
  685. public virtual int CompareTo(BsonDocument rhs)
  686. {
  687. if (rhs == null) { return 1; }
  688. // lhs and rhs might be subclasses of BsonDocument
  689. using (var lhsEnumerator = Elements.GetEnumerator())
  690. using (var rhsEnumerator = rhs.Elements.GetEnumerator())
  691. {
  692. while (true)
  693. {
  694. var lhsHasNext = lhsEnumerator.MoveNext();
  695. var rhsHasNext = rhsEnumerator.MoveNext();
  696. if (!lhsHasNext && !rhsHasNext) { return 0; }
  697. if (!lhsHasNext) { return -1; }
  698. if (!rhsHasNext) { return 1; }
  699. var lhsElement = lhsEnumerator.Current;
  700. var rhsElement = rhsEnumerator.Current;
  701. var result = lhsElement.Name.CompareTo(rhsElement.Name);
  702. if (result != 0) { return result; }
  703. result = lhsElement.Value.CompareTo(rhsElement.Value);
  704. if (result != 0) { return result; }
  705. }
  706. }
  707. }
  708. /// <summary>
  709. /// Compares the BsonDocument to another BsonValue.
  710. /// </summary>
  711. /// <param name="other">The other BsonValue.</param>
  712. /// <returns>A 32-bit signed integer that indicates whether this BsonDocument is less than, equal to, or greather than the other BsonValue.</returns>
  713. public override int CompareTo(BsonValue other)
  714. {
  715. if (other == null) { return 1; }
  716. var otherDocument = other as BsonDocument;
  717. if (otherDocument != null)
  718. {
  719. return CompareTo(otherDocument);
  720. }
  721. return CompareTypeTo(other);
  722. }
  723. /// <summary>
  724. /// Tests whether the document contains an element with the specified name.
  725. /// </summary>
  726. /// <param name="name">The name of the element to look for.</param>
  727. /// <returns>True if the document contains an element with the specified name.</returns>
  728. public virtual bool Contains(string name)
  729. {
  730. return _indexes.ContainsKey(name);
  731. }
  732. /// <summary>
  733. /// Tests whether the document contains an element with the specified value.
  734. /// </summary>
  735. /// <param name="value">The value of the element to look for.</param>
  736. /// <returns>True if the document contains an element with the specified value.</returns>
  737. public virtual bool ContainsValue(BsonValue value)
  738. {
  739. if (value == null)
  740. {
  741. throw new ArgumentNullException("value");
  742. }
  743. return _elements.Any(e => e.Value == value);
  744. }
  745. /// <summary>
  746. /// Creates a deep clone of the document (see also Clone).
  747. /// </summary>
  748. /// <returns>A deep clone of the document.</returns>
  749. public override BsonValue DeepClone()
  750. {
  751. BsonDocument clone = new BsonDocument();
  752. foreach (BsonElement element in _elements)
  753. {
  754. clone.Add(element.DeepClone());
  755. }
  756. return clone;
  757. }
  758. /// <summary>
  759. /// Deserializes the document from a BsonReader.
  760. /// </summary>
  761. /// <param name="bsonReader">The BsonReader.</param>
  762. /// <param name="nominalType">The nominal type of the object (ignored, but should be BsonDocument).</param>
  763. /// <param name="options">The serialization options (ignored).</param>
  764. /// <returns>The document (which has now been initialized by deserialization), or null.</returns>
  765. [Obsolete("Deserialize was intended to be private and will become private in a future release.")]
  766. public virtual object Deserialize(BsonReader bsonReader, Type nominalType, IBsonSerializationOptions options)
  767. {
  768. return BsonDocumentSerializer.Instance.Deserialize(bsonReader, nominalType, options);
  769. }
  770. /// <summary>
  771. /// Gets the Id of the document.
  772. /// </summary>
  773. /// <param name="id">The Id of the document (the RawValue if it has one, otherwise the element Value).</param>
  774. /// <param name="idNominalType">The nominal type of the Id.</param>
  775. /// <param name="idGenerator">The IdGenerator for the Id (or null).</param>
  776. /// <returns>True (a BsonDocument either has an Id member or one can be added).</returns>
  777. [Obsolete("GetDocumentId was intended to be private and will become private in a future release. Use document[\"_id\"] or document.GetValue(\"_id\") instead.")]
  778. public virtual bool GetDocumentId(out object id, out Type idNominalType, out IIdGenerator idGenerator)
  779. {
  780. var idProvider = (IBsonIdProvider)BsonDocumentSerializer.Instance;
  781. return idProvider.GetDocumentId(this, out id, out idNominalType, out idGenerator);
  782. }
  783. /// <summary>
  784. /// Compares this document to another document.
  785. /// </summary>
  786. /// <param name="obj">The other document.</param>
  787. /// <returns>True if the two documents are equal.</returns>
  788. public bool Equals(BsonDocument obj)
  789. {
  790. return Equals((object)obj); // handles obj == null correctly
  791. }
  792. /// <summary>
  793. /// Compares this BsonDocument to another object.
  794. /// </summary>
  795. /// <param name="obj">The other object.</param>
  796. /// <returns>True if the other object is a BsonDocument and equal to this one.</returns>
  797. public override bool Equals(object obj)
  798. {
  799. if (object.ReferenceEquals(obj, null) || !(obj is BsonDocument)) { return false; }
  800. // lhs and rhs might be subclasses of BsonDocument
  801. var rhs = (BsonDocument)obj;
  802. return Elements.SequenceEqual(rhs.Elements);
  803. }
  804. /// <summary>
  805. /// Gets an element of this document.
  806. /// </summary>
  807. /// <param name="index">The zero based index of the element.</param>
  808. /// <returns>The element.</returns>
  809. public virtual BsonElement GetElement(int index)
  810. {
  811. return _elements[index];
  812. }
  813. /// <summary>
  814. /// Gets an element of this document.
  815. /// </summary>
  816. /// <param name="name">The name of the element.</param>
  817. /// <returns>A BsonElement.</returns>
  818. public virtual BsonElement GetElement(string name)
  819. {
  820. if (name == null)
  821. {
  822. throw new ArgumentNullException("name");
  823. }
  824. int index;
  825. if (_indexes.TryGetValue(name, out index))
  826. {
  827. return _elements[index];
  828. }
  829. else
  830. {
  831. string message = string.Format("Element '{0}' not found.", name);
  832. throw new KeyNotFoundException(message);
  833. }
  834. }
  835. /// <summary>
  836. /// Gets an enumerator that can be used to enumerate the elements of this document.
  837. /// </summary>
  838. /// <returns>An enumerator.</returns>
  839. public virtual IEnumerator<BsonElement> GetEnumerator()
  840. {
  841. return _elements.GetEnumerator();
  842. }
  843. /// <summary>
  844. /// Gets the hash code.
  845. /// </summary>
  846. /// <returns>The hash code.</returns>
  847. public override int GetHashCode()
  848. {
  849. return new Hasher()
  850. .Hash(BsonType)
  851. .HashElements(Elements)
  852. .GetHashCode();
  853. }
  854. /// <summary>
  855. /// Gets the value of an element.
  856. /// </summary>
  857. /// <param name="index">The zero based index of the element.</param>
  858. /// <returns>The value of the element.</returns>
  859. public virtual BsonValue GetValue(int index)
  860. {
  861. return this[index];
  862. }
  863. /// <summary>
  864. /// Gets the value of an element.
  865. /// </summary>
  866. /// <param name="name">The name of the element.</param>
  867. /// <returns>The value of the element.</returns>
  868. public virtual BsonValue GetValue(string name)
  869. {
  870. if (name == null)
  871. {
  872. throw new ArgumentNullException("name");
  873. }
  874. return this[name];
  875. }
  876. /// <summary>
  877. /// Gets the value of an element or a default value if the element is not found.
  878. /// </summary>
  879. /// <param name="name">The name of the element.</param>
  880. /// <param name="defaultValue">The default value returned if the element is not found.</param>
  881. /// <returns>The value of the element or the default value if the element is not found.</returns>
  882. public virtual BsonValue GetValue(string name, BsonValue defaultValue)
  883. {
  884. if (name == null)
  885. {
  886. throw new ArgumentNullException("name");
  887. }
  888. int index;
  889. if (_indexes.TryGetValue(name, out index))
  890. {
  891. return _elements[index].Value;
  892. }
  893. else
  894. {
  895. return defaultValue;
  896. }
  897. }
  898. /// <summary>
  899. /// Inserts a new element at a specified position.
  900. /// </summary>
  901. /// <param name="index">The position of the new element.</param>
  902. /// <param name="element">The element.</param>
  903. public virtual void InsertAt(int index, BsonElement element)
  904. {
  905. if (element == null)
  906. {
  907. throw new ArgumentNullException("element");
  908. }
  909. if (_indexes.ContainsKey(element.Name) && !_allowDuplicateNames)
  910. {
  911. var message = string.Format("Duplicate element name '{0}' not allowed.", element.Name);
  912. throw new InvalidOperationException(message);
  913. }
  914. else
  915. {
  916. _elements.Insert(index, element);
  917. RebuildDictionary();
  918. }
  919. }
  920. /// <summary>
  921. /// Merges another document into this one. Existing elements are not overwritten.
  922. /// </summary>
  923. /// <param name="document">The other document.</param>
  924. /// <returns>The document (so method calls can be chained).</returns>
  925. public virtual BsonDocument Merge(BsonDocument document)
  926. {
  927. Merge(document, false); // don't overwriteExistingElements
  928. return this;
  929. }
  930. /// <summary>
  931. /// Merges another document into this one, specifying whether existing elements are overwritten.
  932. /// </summary>
  933. /// <param name="document">The other document.</param>
  934. /// <param name="overwriteExistingElements">Whether to overwrite existing elements.</param>
  935. /// <returns>The document (so method calls can be chained).</returns>
  936. public virtual BsonDocument Merge(BsonDocument document, bool overwriteExistingElements)
  937. {
  938. if (document != null)
  939. {
  940. foreach (BsonElement element in document)
  941. {
  942. if (overwriteExistingElements || !Contains(element.Name))
  943. {
  944. this[element.Name] = element.Value;
  945. }
  946. }
  947. }
  948. return this;
  949. }
  950. /// <summary>
  951. /// Removes an element from this document (if duplicate element names are allowed
  952. /// then all elements with this name will be removed).
  953. /// </summary>
  954. /// <param name="name">The name of the element to remove.</param>
  955. public virtual void Remove(string name)
  956. {
  957. if (name == null)
  958. {
  959. throw new ArgumentNullException("name");
  960. }
  961. if (_indexes.ContainsKey(name))
  962. {
  963. _elements.RemoveAll(e => e.Name == name);
  964. RebuildDictionary();
  965. }
  966. }
  967. /// <summary>
  968. /// Removes an element from this document.
  969. /// </summary>
  970. /// <param name="index">The zero based index of the element to remove.</param>
  971. public virtual void RemoveAt(int index)
  972. {
  973. _elements.RemoveAt(index);
  974. RebuildDictionary();
  975. }
  976. /// <summary>
  977. /// Removes an element from this document.
  978. /// </summary>
  979. /// <param name="element">The element to remove.</param>
  980. public virtual void RemoveElement(BsonElement element)
  981. {
  982. if (element == null)
  983. {
  984. throw new ArgumentNullException("element");
  985. }
  986. _elements.Remove(element);
  987. RebuildDictionary();
  988. }
  989. /// <summary>
  990. /// Serializes this document to a BsonWriter.
  991. /// </summary>
  992. /// <param name="bsonWriter">The writer.</param>
  993. /// <param name="nominalType">The nominalType.</param>
  994. /// <param name="options">The serialization options (can be null).</param>
  995. [Obsolete("Serialize was intended to be private and will become private in a future release.")]
  996. public virtual void Serialize(BsonWriter bsonWriter, Type nominalType, IBsonSerializationOptions options)
  997. {
  998. BsonDocumentSerializer.Instance.Serialize(bsonWriter, nominalType, this, options);
  999. }
  1000. /// <summary>
  1001. /// Sets the value of an element.
  1002. /// </summary>
  1003. /// <param name="index">The zero based index of the element whose value is to be set.</param>
  1004. /// <param name="value">The new value.</param>
  1005. /// <returns>The document (so method calls can be chained).</returns>
  1006. public virtual BsonDocument Set(int index, BsonValue value)
  1007. {
  1008. if (value == null)
  1009. {
  1010. throw new ArgumentNullException("value");
  1011. }
  1012. this[index] = value;
  1013. return this;
  1014. }
  1015. /// <summary>
  1016. /// Sets the value of an element (an element will be added if no element with this name is found).
  1017. /// </summary>
  1018. /// <param name="name">The name of the element whose value is to be set.</param>
  1019. /// <param name="value">The new value.</param>
  1020. /// <returns>The document (so method calls can be chained).</returns>
  1021. public virtual BsonDocument Set(string name, BsonValue value)
  1022. {
  1023. if (name == null)
  1024. {
  1025. throw new ArgumentNullException("name");
  1026. }
  1027. if (value == null)
  1028. {
  1029. throw new ArgumentNullException("value");
  1030. }
  1031. this[name] = value;
  1032. return this;
  1033. }
  1034. /// <summary>
  1035. /// Sets the document Id.
  1036. /// </summary>
  1037. /// <param name="id">The value of the Id.</param>
  1038. [Obsolete("SetDocumentId was intended to be private and will become private in a future release. Use document[\"_id\"] = value or document.Set(\"_id\", value) instead.")]
  1039. public virtual void SetDocumentId(object id)
  1040. {
  1041. var idProvider = (IBsonIdProvider)BsonDocumentSerializer.Instance;
  1042. idProvider.SetDocumentId(this, id);
  1043. }
  1044. /// <summary>
  1045. /// Sets an element of the document (replacing the existing element at that position).
  1046. /// </summary>
  1047. /// <param name="index">The zero based index of the element to replace.</param>
  1048. /// <param name="element">The new element.</param>
  1049. /// <returns>The document.</returns>
  1050. public virtual BsonDocument SetElement(int index, BsonElement element)
  1051. {
  1052. if (element == null)
  1053. {
  1054. throw new ArgumentNullException("element");
  1055. }
  1056. _elements[index] = element;
  1057. RebuildDictionary();
  1058. return this;
  1059. }
  1060. /// <summary>
  1061. /// Sets an element of the document (replaces any existing element with the same name or adds a new element if an element with the same name is not found).
  1062. /// </summary>
  1063. /// <param name="element">The new element.</param>
  1064. /// <returns>The document.</returns>
  1065. public virtual BsonDocument SetElement(BsonElement element)
  1066. {
  1067. if (element == null)
  1068. {
  1069. throw new ArgumentNullException("element");
  1070. }
  1071. int index;
  1072. if (_indexes.TryGetValue(element.Name, out index))
  1073. {
  1074. _elements[index] = element;
  1075. }
  1076. else
  1077. {
  1078. Add(element);
  1079. }
  1080. return this;
  1081. }
  1082. /// <summary>
  1083. /// Converts the BsonDocument to a Dictionary&lt;string, object&gt;.
  1084. /// </summary>
  1085. /// <returns>A dictionary.</returns>
  1086. public Dictionary<string, object> ToDictionary()
  1087. {
  1088. var options = new BsonTypeMapperOptions
  1089. {
  1090. DuplicateNameHandling = DuplicateNameHandling.ThrowException,
  1091. MapBsonArrayTo = typeof(object[]), // TODO: should this be List<object>?
  1092. MapBsonDocumentTo = typeof(Dictionary<string, object>),
  1093. MapOldBinaryToByteArray = false
  1094. };
  1095. return (Dictionary<string, object>)BsonTypeMapper.MapToDotNetValue(this, options);
  1096. }
  1097. /// <summary>
  1098. /// Converts the BsonDocument to a Hashtable.
  1099. /// </summary>
  1100. /// <returns>A hashtable.</returns>
  1101. public Hashtable ToHashtable()
  1102. {
  1103. var options = new BsonTypeMapperOptions
  1104. {
  1105. DuplicateNameHandling = DuplicateNameHandling.ThrowException,
  1106. MapBsonArrayTo = typeof(object[]), // TODO: should this be ArrayList?
  1107. MapBsonDocumentTo = typeof(Hashtable),
  1108. MapOldBinaryToByteArray = false
  1109. };
  1110. return (Hashtable)BsonTypeMapper.MapToDotNetValue(this, options);
  1111. }
  1112. /// <summary>
  1113. /// Returns a string representation of the document.
  1114. /// </summary>
  1115. /// <returns>A string representation of the document.</returns>
  1116. public override string ToString()
  1117. {
  1118. return this.ToJson();
  1119. }
  1120. /// <summary>
  1121. /// Tries to get an element of this document.
  1122. /// </summary>
  1123. /// <param name="name">The name of the element.</param>
  1124. /// <param name="value">The element.</param>
  1125. /// <returns>True if an element with that name was found.</returns>
  1126. public virtual bool TryGetElement(string name, out BsonElement value)
  1127. {
  1128. if (name == null)
  1129. {
  1130. throw new ArgumentNullException("name");
  1131. }
  1132. int index;
  1133. if (_indexes.TryGetValue(name, out index))
  1134. {
  1135. value = _elements[index];
  1136. return true;
  1137. }
  1138. else
  1139. {
  1140. value = null;
  1141. return false;
  1142. }
  1143. }
  1144. /// <summary>
  1145. /// Tries to get the value of an element of this document.
  1146. /// </summary>
  1147. /// <param name="name">The name of the element.</param>
  1148. /// <param name="value">The value of the element.</param>
  1149. /// <returns>True if an element with that name was found.</returns>
  1150. public virtual bool TryGetValue(string name, out BsonValue value)
  1151. {
  1152. if (name == null)
  1153. {
  1154. throw new ArgumentNullException("name");
  1155. }
  1156. int index;
  1157. if (_indexes.TryGetValue(name, out index))
  1158. {
  1159. value = _elements[index].Value;
  1160. return true;
  1161. }
  1162. else
  1163. {
  1164. value = null;
  1165. return false;
  1166. }
  1167. }
  1168. /// <summary>
  1169. /// Writes the document to a BsonWriter.
  1170. /// </summary>
  1171. /// <param name="bsonWriter">The writer.</param>
  1172. [Obsolete("Use BsonSerializer.Serialize<BsonDocument> instead.")]
  1173. public new void WriteTo(BsonWriter bsonWriter)
  1174. {
  1175. BsonSerializer.Serialize(bsonWriter, this);
  1176. }
  1177. /// <summary>
  1178. /// Writes the document to a BsonBuffer.
  1179. /// </summary>
  1180. /// <param name="buffer">The buffer.</param>
  1181. [Obsolete("Use BsonSerializer.Serialize<BsonDocument> instead.")]
  1182. public void WriteTo(BsonBuffer buffer)
  1183. {
  1184. using (BsonWriter bsonWriter = BsonWriter.Create(buffer))
  1185. {
  1186. BsonSerializer.Serialize(bsonWriter, this);
  1187. }
  1188. }
  1189. /// <summary>
  1190. /// Writes the document to a Stream.
  1191. /// </summary>
  1192. /// <param name="stream">The stream.</param>
  1193. [Obsolete("Use BsonSerializer.Serialize<BsonDocument> instead.")]
  1194. public void WriteTo(Stream stream)
  1195. {
  1196. using (BsonWriter bsonWriter = BsonWriter.Create(stream))
  1197. {
  1198. BsonSerializer.Serialize(bsonWriter, this);
  1199. }
  1200. }
  1201. /// <summary>
  1202. /// Writes the document to a file.
  1203. /// </summary>
  1204. /// <param name="filename">The name of the file.</param>
  1205. [Obsolete("Use BsonSerializer.Serialize<BsonDocument> instead.")]
  1206. public void WriteTo(string filename)
  1207. {
  1208. using (FileStream stream = new FileStream(filename, FileMode.Create, FileAccess.Write))
  1209. {
  1210. using (BsonWriter bsonWriter = BsonWriter.Create(stream))
  1211. {
  1212. BsonSerializer.Serialize(bsonWriter, this);
  1213. }
  1214. }
  1215. }
  1216. // private methods
  1217. private void RebuildDictionary()
  1218. {
  1219. _indexes.Clear();
  1220. for (int index = 0; index < _elements.Count; index++)
  1221. {
  1222. BsonElement element = _elements[index];
  1223. if (!_indexes.ContainsKey(element.Name))
  1224. {
  1225. _indexes.Add(element.Name, index);
  1226. }
  1227. }
  1228. }
  1229. // explicit interface implementations
  1230. BsonDocument IConvertibleToBsonDocument.ToBsonDocument()
  1231. {
  1232. return this;
  1233. }
  1234. IEnumerator IEnumerable.GetEnumerator()
  1235. {
  1236. return GetEnumerator();
  1237. }
  1238. }
  1239. }