ObjectId.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. /* Copyright 2010-present 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.Diagnostics;
  17. using System.Runtime.CompilerServices;
  18. using System.Security;
  19. using System.Threading;
  20. namespace MongoDB.Bson
  21. {
  22. /// <summary>
  23. /// Represents an ObjectId (see also BsonObjectId).
  24. /// </summary>
  25. #if NET452
  26. [Serializable]
  27. #endif
  28. public struct ObjectId : IComparable<ObjectId>, IEquatable<ObjectId>, IConvertible
  29. {
  30. // private static fields
  31. private static readonly ObjectId __emptyInstance = default(ObjectId);
  32. private static readonly int __staticMachine = (GetMachineHash() + GetAppDomainId()) & 0x00ffffff;
  33. private static readonly short __staticPid = GetPid();
  34. private static int __staticIncrement = (new Random()).Next();
  35. // private fields
  36. private readonly int _a;
  37. private readonly int _b;
  38. private readonly int _c;
  39. // constructors
  40. /// <summary>
  41. /// Initializes a new instance of the ObjectId class.
  42. /// </summary>
  43. /// <param name="bytes">The bytes.</param>
  44. public ObjectId(byte[] bytes)
  45. {
  46. if (bytes == null)
  47. {
  48. throw new ArgumentNullException("bytes");
  49. }
  50. if (bytes.Length != 12)
  51. {
  52. throw new ArgumentException("Byte array must be 12 bytes long", "bytes");
  53. }
  54. FromByteArray(bytes, 0, out _a, out _b, out _c);
  55. }
  56. /// <summary>
  57. /// Initializes a new instance of the ObjectId class.
  58. /// </summary>
  59. /// <param name="bytes">The bytes.</param>
  60. /// <param name="index">The index into the byte array where the ObjectId starts.</param>
  61. internal ObjectId(byte[] bytes, int index)
  62. {
  63. FromByteArray(bytes, index, out _a, out _b, out _c);
  64. }
  65. /// <summary>
  66. /// Initializes a new instance of the ObjectId class.
  67. /// </summary>
  68. /// <param name="timestamp">The timestamp (expressed as a DateTime).</param>
  69. /// <param name="machine">The machine hash.</param>
  70. /// <param name="pid">The PID.</param>
  71. /// <param name="increment">The increment.</param>
  72. public ObjectId(DateTime timestamp, int machine, short pid, int increment)
  73. : this(GetTimestampFromDateTime(timestamp), machine, pid, increment)
  74. {
  75. }
  76. /// <summary>
  77. /// Initializes a new instance of the ObjectId class.
  78. /// </summary>
  79. /// <param name="timestamp">The timestamp.</param>
  80. /// <param name="machine">The machine hash.</param>
  81. /// <param name="pid">The PID.</param>
  82. /// <param name="increment">The increment.</param>
  83. public ObjectId(int timestamp, int machine, short pid, int increment)
  84. {
  85. if ((machine & 0xff000000) != 0)
  86. {
  87. throw new ArgumentOutOfRangeException("machine", "The machine value must be between 0 and 16777215 (it must fit in 3 bytes).");
  88. }
  89. if ((increment & 0xff000000) != 0)
  90. {
  91. throw new ArgumentOutOfRangeException("increment", "The increment value must be between 0 and 16777215 (it must fit in 3 bytes).");
  92. }
  93. _a = timestamp;
  94. _b = (machine << 8) | (((int)pid >> 8) & 0xff);
  95. _c = ((int)pid << 24) | increment;
  96. }
  97. /// <summary>
  98. /// Initializes a new instance of the ObjectId class.
  99. /// </summary>
  100. /// <param name="value">The value.</param>
  101. public ObjectId(string value)
  102. {
  103. if (value == null)
  104. {
  105. throw new ArgumentNullException("value");
  106. }
  107. var bytes = BsonUtils.ParseHexString(value);
  108. FromByteArray(bytes, 0, out _a, out _b, out _c);
  109. }
  110. // public static properties
  111. /// <summary>
  112. /// Gets an instance of ObjectId where the value is empty.
  113. /// </summary>
  114. public static ObjectId Empty
  115. {
  116. get { return __emptyInstance; }
  117. }
  118. // public properties
  119. /// <summary>
  120. /// Gets the timestamp.
  121. /// </summary>
  122. public int Timestamp
  123. {
  124. get { return _a; }
  125. }
  126. /// <summary>
  127. /// Gets the machine.
  128. /// </summary>
  129. public int Machine
  130. {
  131. get { return (_b >> 8) & 0xffffff; }
  132. }
  133. /// <summary>
  134. /// Gets the PID.
  135. /// </summary>
  136. public short Pid
  137. {
  138. get { return (short)(((_b << 8) & 0xff00) | ((_c >> 24) & 0x00ff)); }
  139. }
  140. /// <summary>
  141. /// Gets the increment.
  142. /// </summary>
  143. public int Increment
  144. {
  145. get { return _c & 0xffffff; }
  146. }
  147. /// <summary>
  148. /// Gets the creation time (derived from the timestamp).
  149. /// </summary>
  150. public DateTime CreationTime
  151. {
  152. get { return BsonConstants.UnixEpoch.AddSeconds(Timestamp); }
  153. }
  154. // public operators
  155. /// <summary>
  156. /// Compares two ObjectIds.
  157. /// </summary>
  158. /// <param name="lhs">The first ObjectId.</param>
  159. /// <param name="rhs">The other ObjectId</param>
  160. /// <returns>True if the first ObjectId is less than the second ObjectId.</returns>
  161. public static bool operator <(ObjectId lhs, ObjectId rhs)
  162. {
  163. return lhs.CompareTo(rhs) < 0;
  164. }
  165. /// <summary>
  166. /// Compares two ObjectIds.
  167. /// </summary>
  168. /// <param name="lhs">The first ObjectId.</param>
  169. /// <param name="rhs">The other ObjectId</param>
  170. /// <returns>True if the first ObjectId is less than or equal to the second ObjectId.</returns>
  171. public static bool operator <=(ObjectId lhs, ObjectId rhs)
  172. {
  173. return lhs.CompareTo(rhs) <= 0;
  174. }
  175. /// <summary>
  176. /// Compares two ObjectIds.
  177. /// </summary>
  178. /// <param name="lhs">The first ObjectId.</param>
  179. /// <param name="rhs">The other ObjectId.</param>
  180. /// <returns>True if the two ObjectIds are equal.</returns>
  181. public static bool operator ==(ObjectId lhs, ObjectId rhs)
  182. {
  183. return lhs.Equals(rhs);
  184. }
  185. /// <summary>
  186. /// Compares two ObjectIds.
  187. /// </summary>
  188. /// <param name="lhs">The first ObjectId.</param>
  189. /// <param name="rhs">The other ObjectId.</param>
  190. /// <returns>True if the two ObjectIds are not equal.</returns>
  191. public static bool operator !=(ObjectId lhs, ObjectId rhs)
  192. {
  193. return !(lhs == rhs);
  194. }
  195. /// <summary>
  196. /// Compares two ObjectIds.
  197. /// </summary>
  198. /// <param name="lhs">The first ObjectId.</param>
  199. /// <param name="rhs">The other ObjectId</param>
  200. /// <returns>True if the first ObjectId is greather than or equal to the second ObjectId.</returns>
  201. public static bool operator >=(ObjectId lhs, ObjectId rhs)
  202. {
  203. return lhs.CompareTo(rhs) >= 0;
  204. }
  205. /// <summary>
  206. /// Compares two ObjectIds.
  207. /// </summary>
  208. /// <param name="lhs">The first ObjectId.</param>
  209. /// <param name="rhs">The other ObjectId</param>
  210. /// <returns>True if the first ObjectId is greather than the second ObjectId.</returns>
  211. public static bool operator >(ObjectId lhs, ObjectId rhs)
  212. {
  213. return lhs.CompareTo(rhs) > 0;
  214. }
  215. // public static methods
  216. /// <summary>
  217. /// Generates a new ObjectId with a unique value.
  218. /// </summary>
  219. /// <returns>An ObjectId.</returns>
  220. public static ObjectId GenerateNewId()
  221. {
  222. return GenerateNewId(GetTimestampFromDateTime(DateTime.UtcNow));
  223. }
  224. /// <summary>
  225. /// Generates a new ObjectId with a unique value (with the timestamp component based on a given DateTime).
  226. /// </summary>
  227. /// <param name="timestamp">The timestamp component (expressed as a DateTime).</param>
  228. /// <returns>An ObjectId.</returns>
  229. public static ObjectId GenerateNewId(DateTime timestamp)
  230. {
  231. return GenerateNewId(GetTimestampFromDateTime(timestamp));
  232. }
  233. /// <summary>
  234. /// Generates a new ObjectId with a unique value (with the given timestamp).
  235. /// </summary>
  236. /// <param name="timestamp">The timestamp component.</param>
  237. /// <returns>An ObjectId.</returns>
  238. public static ObjectId GenerateNewId(int timestamp)
  239. {
  240. int increment = Interlocked.Increment(ref __staticIncrement) & 0x00ffffff; // only use low order 3 bytes
  241. return new ObjectId(timestamp, __staticMachine, __staticPid, increment);
  242. }
  243. /// <summary>
  244. /// Packs the components of an ObjectId into a byte array.
  245. /// </summary>
  246. /// <param name="timestamp">The timestamp.</param>
  247. /// <param name="machine">The machine hash.</param>
  248. /// <param name="pid">The PID.</param>
  249. /// <param name="increment">The increment.</param>
  250. /// <returns>A byte array.</returns>
  251. public static byte[] Pack(int timestamp, int machine, short pid, int increment)
  252. {
  253. if ((machine & 0xff000000) != 0)
  254. {
  255. throw new ArgumentOutOfRangeException("machine", "The machine value must be between 0 and 16777215 (it must fit in 3 bytes).");
  256. }
  257. if ((increment & 0xff000000) != 0)
  258. {
  259. throw new ArgumentOutOfRangeException("increment", "The increment value must be between 0 and 16777215 (it must fit in 3 bytes).");
  260. }
  261. byte[] bytes = new byte[12];
  262. bytes[0] = (byte)(timestamp >> 24);
  263. bytes[1] = (byte)(timestamp >> 16);
  264. bytes[2] = (byte)(timestamp >> 8);
  265. bytes[3] = (byte)(timestamp);
  266. bytes[4] = (byte)(machine >> 16);
  267. bytes[5] = (byte)(machine >> 8);
  268. bytes[6] = (byte)(machine);
  269. bytes[7] = (byte)(pid >> 8);
  270. bytes[8] = (byte)(pid);
  271. bytes[9] = (byte)(increment >> 16);
  272. bytes[10] = (byte)(increment >> 8);
  273. bytes[11] = (byte)(increment);
  274. return bytes;
  275. }
  276. /// <summary>
  277. /// Parses a string and creates a new ObjectId.
  278. /// </summary>
  279. /// <param name="s">The string value.</param>
  280. /// <returns>A ObjectId.</returns>
  281. public static ObjectId Parse(string s)
  282. {
  283. if (s == null)
  284. {
  285. throw new ArgumentNullException("s");
  286. }
  287. ObjectId objectId;
  288. if (TryParse(s, out objectId))
  289. {
  290. return objectId;
  291. }
  292. else
  293. {
  294. var message = string.Format("'{0}' is not a valid 24 digit hex string.", s);
  295. throw new FormatException(message);
  296. }
  297. }
  298. /// <summary>
  299. /// Tries to parse a string and create a new ObjectId.
  300. /// </summary>
  301. /// <param name="s">The string value.</param>
  302. /// <param name="objectId">The new ObjectId.</param>
  303. /// <returns>True if the string was parsed successfully.</returns>
  304. public static bool TryParse(string s, out ObjectId objectId)
  305. {
  306. // don't throw ArgumentNullException if s is null
  307. if (s != null && s.Length == 24)
  308. {
  309. byte[] bytes;
  310. if (BsonUtils.TryParseHexString(s, out bytes))
  311. {
  312. objectId = new ObjectId(bytes);
  313. return true;
  314. }
  315. }
  316. objectId = default(ObjectId);
  317. return false;
  318. }
  319. /// <summary>
  320. /// Unpacks a byte array into the components of an ObjectId.
  321. /// </summary>
  322. /// <param name="bytes">A byte array.</param>
  323. /// <param name="timestamp">The timestamp.</param>
  324. /// <param name="machine">The machine hash.</param>
  325. /// <param name="pid">The PID.</param>
  326. /// <param name="increment">The increment.</param>
  327. public static void Unpack(byte[] bytes, out int timestamp, out int machine, out short pid, out int increment)
  328. {
  329. if (bytes == null)
  330. {
  331. throw new ArgumentNullException("bytes");
  332. }
  333. if (bytes.Length != 12)
  334. {
  335. throw new ArgumentOutOfRangeException("bytes", "Byte array must be 12 bytes long.");
  336. }
  337. timestamp = (bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + bytes[3];
  338. machine = (bytes[4] << 16) + (bytes[5] << 8) + bytes[6];
  339. pid = (short)((bytes[7] << 8) + bytes[8]);
  340. increment = (bytes[9] << 16) + (bytes[10] << 8) + bytes[11];
  341. }
  342. // private static methods
  343. private static int GetAppDomainId()
  344. {
  345. #if NETSTANDARD1_5 || NETSTANDARD1_6
  346. return 1;
  347. #else
  348. return AppDomain.CurrentDomain.Id;
  349. #endif
  350. }
  351. /// <summary>
  352. /// Gets the current process id. This method exists because of how CAS operates on the call stack, checking
  353. /// for permissions before executing the method. Hence, if we inlined this call, the calling method would not execute
  354. /// before throwing an exception requiring the try/catch at an even higher level that we don't necessarily control.
  355. /// </summary>
  356. [MethodImpl(MethodImplOptions.NoInlining)]
  357. private static int GetCurrentProcessId()
  358. {
  359. return Process.GetCurrentProcess().Id;
  360. }
  361. private static int GetMachineHash()
  362. {
  363. // use instead of Dns.HostName so it will work offline
  364. var machineName = GetMachineName();
  365. return 0x00ffffff & machineName.GetHashCode(); // use first 3 bytes of hash
  366. }
  367. private static string GetMachineName()
  368. {
  369. return Environment.MachineName;
  370. }
  371. private static short GetPid()
  372. {
  373. try
  374. {
  375. return (short)GetCurrentProcessId(); // use low order two bytes only
  376. }
  377. catch (SecurityException)
  378. {
  379. return 0;
  380. }
  381. }
  382. private static int GetTimestampFromDateTime(DateTime timestamp)
  383. {
  384. var secondsSinceEpoch = (long)Math.Floor((BsonUtils.ToUniversalTime(timestamp) - BsonConstants.UnixEpoch).TotalSeconds);
  385. if (secondsSinceEpoch < int.MinValue || secondsSinceEpoch > int.MaxValue)
  386. {
  387. throw new ArgumentOutOfRangeException("timestamp");
  388. }
  389. return (int)secondsSinceEpoch;
  390. }
  391. private static void FromByteArray(byte[] bytes, int offset, out int a, out int b, out int c)
  392. {
  393. a = (bytes[offset] << 24) | (bytes[offset + 1] << 16) | (bytes[offset + 2] << 8) | bytes[offset + 3];
  394. b = (bytes[offset + 4] << 24) | (bytes[offset + 5] << 16) | (bytes[offset + 6] << 8) | bytes[offset + 7];
  395. c = (bytes[offset + 8] << 24) | (bytes[offset + 9] << 16) | (bytes[offset + 10] << 8) | bytes[offset + 11];
  396. }
  397. // public methods
  398. /// <summary>
  399. /// Compares this ObjectId to another ObjectId.
  400. /// </summary>
  401. /// <param name="other">The other ObjectId.</param>
  402. /// <returns>A 32-bit signed integer that indicates whether this ObjectId is less than, equal to, or greather than the other.</returns>
  403. public int CompareTo(ObjectId other)
  404. {
  405. int result = ((uint)_a).CompareTo((uint)other._a);
  406. if (result != 0) { return result; }
  407. result = ((uint)_b).CompareTo((uint)other._b);
  408. if (result != 0) { return result; }
  409. return ((uint)_c).CompareTo((uint)other._c);
  410. }
  411. /// <summary>
  412. /// Compares this ObjectId to another ObjectId.
  413. /// </summary>
  414. /// <param name="rhs">The other ObjectId.</param>
  415. /// <returns>True if the two ObjectIds are equal.</returns>
  416. public bool Equals(ObjectId rhs)
  417. {
  418. return
  419. _a == rhs._a &&
  420. _b == rhs._b &&
  421. _c == rhs._c;
  422. }
  423. /// <summary>
  424. /// Compares this ObjectId to another object.
  425. /// </summary>
  426. /// <param name="obj">The other object.</param>
  427. /// <returns>True if the other object is an ObjectId and equal to this one.</returns>
  428. public override bool Equals(object obj)
  429. {
  430. if (obj is ObjectId)
  431. {
  432. return Equals((ObjectId)obj);
  433. }
  434. else
  435. {
  436. return false;
  437. }
  438. }
  439. /// <summary>
  440. /// Gets the hash code.
  441. /// </summary>
  442. /// <returns>The hash code.</returns>
  443. public override int GetHashCode()
  444. {
  445. int hash = 17;
  446. hash = 37 * hash + _a.GetHashCode();
  447. hash = 37 * hash + _b.GetHashCode();
  448. hash = 37 * hash + _c.GetHashCode();
  449. return hash;
  450. }
  451. /// <summary>
  452. /// Converts the ObjectId to a byte array.
  453. /// </summary>
  454. /// <returns>A byte array.</returns>
  455. public byte[] ToByteArray()
  456. {
  457. var bytes = new byte[12];
  458. ToByteArray(bytes, 0);
  459. return bytes;
  460. }
  461. /// <summary>
  462. /// Converts the ObjectId to a byte array.
  463. /// </summary>
  464. /// <param name="destination">The destination.</param>
  465. /// <param name="offset">The offset.</param>
  466. public void ToByteArray(byte[] destination, int offset)
  467. {
  468. if (destination == null)
  469. {
  470. throw new ArgumentNullException("destination");
  471. }
  472. if (offset + 12 > destination.Length)
  473. {
  474. throw new ArgumentException("Not enough room in destination buffer.", "offset");
  475. }
  476. destination[offset + 0] = (byte)(_a >> 24);
  477. destination[offset + 1] = (byte)(_a >> 16);
  478. destination[offset + 2] = (byte)(_a >> 8);
  479. destination[offset + 3] = (byte)(_a);
  480. destination[offset + 4] = (byte)(_b >> 24);
  481. destination[offset + 5] = (byte)(_b >> 16);
  482. destination[offset + 6] = (byte)(_b >> 8);
  483. destination[offset + 7] = (byte)(_b);
  484. destination[offset + 8] = (byte)(_c >> 24);
  485. destination[offset + 9] = (byte)(_c >> 16);
  486. destination[offset + 10] = (byte)(_c >> 8);
  487. destination[offset + 11] = (byte)(_c);
  488. }
  489. /// <summary>
  490. /// Returns a string representation of the value.
  491. /// </summary>
  492. /// <returns>A string representation of the value.</returns>
  493. public override string ToString()
  494. {
  495. var c = new char[24];
  496. c[0] = BsonUtils.ToHexChar((_a >> 28) & 0x0f);
  497. c[1] = BsonUtils.ToHexChar((_a >> 24) & 0x0f);
  498. c[2] = BsonUtils.ToHexChar((_a >> 20) & 0x0f);
  499. c[3] = BsonUtils.ToHexChar((_a >> 16) & 0x0f);
  500. c[4] = BsonUtils.ToHexChar((_a >> 12) & 0x0f);
  501. c[5] = BsonUtils.ToHexChar((_a >> 8) & 0x0f);
  502. c[6] = BsonUtils.ToHexChar((_a >> 4) & 0x0f);
  503. c[7] = BsonUtils.ToHexChar(_a & 0x0f);
  504. c[8] = BsonUtils.ToHexChar((_b >> 28) & 0x0f);
  505. c[9] = BsonUtils.ToHexChar((_b >> 24) & 0x0f);
  506. c[10] = BsonUtils.ToHexChar((_b >> 20) & 0x0f);
  507. c[11] = BsonUtils.ToHexChar((_b >> 16) & 0x0f);
  508. c[12] = BsonUtils.ToHexChar((_b >> 12) & 0x0f);
  509. c[13] = BsonUtils.ToHexChar((_b >> 8) & 0x0f);
  510. c[14] = BsonUtils.ToHexChar((_b >> 4) & 0x0f);
  511. c[15] = BsonUtils.ToHexChar(_b & 0x0f);
  512. c[16] = BsonUtils.ToHexChar((_c >> 28) & 0x0f);
  513. c[17] = BsonUtils.ToHexChar((_c >> 24) & 0x0f);
  514. c[18] = BsonUtils.ToHexChar((_c >> 20) & 0x0f);
  515. c[19] = BsonUtils.ToHexChar((_c >> 16) & 0x0f);
  516. c[20] = BsonUtils.ToHexChar((_c >> 12) & 0x0f);
  517. c[21] = BsonUtils.ToHexChar((_c >> 8) & 0x0f);
  518. c[22] = BsonUtils.ToHexChar((_c >> 4) & 0x0f);
  519. c[23] = BsonUtils.ToHexChar(_c & 0x0f);
  520. return new string(c);
  521. }
  522. // explicit IConvertible implementation
  523. TypeCode IConvertible.GetTypeCode()
  524. {
  525. return TypeCode.Object;
  526. }
  527. bool IConvertible.ToBoolean(IFormatProvider provider)
  528. {
  529. throw new InvalidCastException();
  530. }
  531. byte IConvertible.ToByte(IFormatProvider provider)
  532. {
  533. throw new InvalidCastException();
  534. }
  535. char IConvertible.ToChar(IFormatProvider provider)
  536. {
  537. throw new InvalidCastException();
  538. }
  539. DateTime IConvertible.ToDateTime(IFormatProvider provider)
  540. {
  541. throw new InvalidCastException();
  542. }
  543. decimal IConvertible.ToDecimal(IFormatProvider provider)
  544. {
  545. throw new InvalidCastException();
  546. }
  547. double IConvertible.ToDouble(IFormatProvider provider)
  548. {
  549. throw new InvalidCastException();
  550. }
  551. short IConvertible.ToInt16(IFormatProvider provider)
  552. {
  553. throw new InvalidCastException();
  554. }
  555. int IConvertible.ToInt32(IFormatProvider provider)
  556. {
  557. throw new InvalidCastException();
  558. }
  559. long IConvertible.ToInt64(IFormatProvider provider)
  560. {
  561. throw new InvalidCastException();
  562. }
  563. sbyte IConvertible.ToSByte(IFormatProvider provider)
  564. {
  565. throw new InvalidCastException();
  566. }
  567. float IConvertible.ToSingle(IFormatProvider provider)
  568. {
  569. throw new InvalidCastException();
  570. }
  571. string IConvertible.ToString(IFormatProvider provider)
  572. {
  573. return ToString();
  574. }
  575. object IConvertible.ToType(Type conversionType, IFormatProvider provider)
  576. {
  577. switch (Type.GetTypeCode(conversionType))
  578. {
  579. case TypeCode.String:
  580. return ((IConvertible)this).ToString(provider);
  581. case TypeCode.Object:
  582. if (conversionType == typeof(object) || conversionType == typeof(ObjectId))
  583. {
  584. return this;
  585. }
  586. if (conversionType == typeof(BsonObjectId))
  587. {
  588. return new BsonObjectId(this);
  589. }
  590. if (conversionType == typeof(BsonString))
  591. {
  592. return new BsonString(((IConvertible)this).ToString(provider));
  593. }
  594. break;
  595. }
  596. throw new InvalidCastException();
  597. }
  598. ushort IConvertible.ToUInt16(IFormatProvider provider)
  599. {
  600. throw new InvalidCastException();
  601. }
  602. uint IConvertible.ToUInt32(IFormatProvider provider)
  603. {
  604. throw new InvalidCastException();
  605. }
  606. ulong IConvertible.ToUInt64(IFormatProvider provider)
  607. {
  608. throw new InvalidCastException();
  609. }
  610. }
  611. }