/* Copyright 2010-2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.Text.RegularExpressions; using MongoDB.Bson.IO; using MongoDB.Bson.Serialization; namespace MongoDB.Bson { /// /// Represents a BSON value (this is an abstract class, see the various subclasses). /// [Serializable] public abstract class BsonValue : IComparable, IConvertible, IEquatable { // private static fields private static Dictionary __bsonTypeSortOrder = new Dictionary { { BsonType.MinKey, 1 }, { BsonType.Undefined, 2 }, { BsonType.Null, 3 }, { BsonType.Double, 4 }, { BsonType.Int32, 4 }, { BsonType.Int64, 4 }, { BsonType.String, 5 }, { BsonType.Symbol, 5 }, { BsonType.Document, 6 }, { BsonType.Array, 7 }, { BsonType.Binary, 8 }, { BsonType.ObjectId, 9 }, { BsonType.Boolean, 10 }, { BsonType.DateTime, 11 }, { BsonType.Timestamp, 11 }, { BsonType.RegularExpression, 12 }, { BsonType.JavaScript, 13 }, // TODO: confirm where JavaScript and JavaScriptWithScope are in the sort order { BsonType.JavaScriptWithScope, 14 }, { BsonType.MaxKey, 15 } }; // private fields private BsonType _bsonType; // constructors /// /// Initializes a new instance of the BsonValue class. /// /// The BsonType of this BsonValue. protected BsonValue(BsonType bsonType) { _bsonType = bsonType; } // public properties /// /// Casts the BsonValue to a Boolean (throws an InvalidCastException if the cast is not valid). /// public bool AsBoolean { get { return ((BsonBoolean)this).Value; } } /// /// Casts the BsonValue to a BsonArray (throws an InvalidCastException if the cast is not valid). /// public BsonArray AsBsonArray { get { return (BsonArray)this; } } /// /// Casts the BsonValue to a BsonBinaryData (throws an InvalidCastException if the cast is not valid). /// public BsonBinaryData AsBsonBinaryData { get { return (BsonBinaryData)this; } } /// /// Casts the BsonValue to a BsonDateTime (throws an InvalidCastException if the cast is not valid). /// public BsonDateTime AsBsonDateTime { get { return (BsonDateTime)this; } } /// /// Casts the BsonValue to a BsonDocument (throws an InvalidCastException if the cast is not valid). /// public BsonDocument AsBsonDocument { get { return (BsonDocument)this; } } /// /// Casts the BsonValue to a BsonJavaScript (throws an InvalidCastException if the cast is not valid). /// public BsonJavaScript AsBsonJavaScript { get { return (BsonJavaScript)this; } } /// /// Casts the BsonValue to a BsonJavaScriptWithScope (throws an InvalidCastException if the cast is not valid). /// public BsonJavaScriptWithScope AsBsonJavaScriptWithScope { get { return (BsonJavaScriptWithScope)this; } } /// /// Casts the BsonValue to a BsonMaxKey (throws an InvalidCastException if the cast is not valid). /// public BsonMaxKey AsBsonMaxKey { get { return (BsonMaxKey)this; } } /// /// Casts the BsonValue to a BsonMinKey (throws an InvalidCastException if the cast is not valid). /// public BsonMinKey AsBsonMinKey { get { return (BsonMinKey)this; } } /// /// Casts the BsonValue to a BsonNull (throws an InvalidCastException if the cast is not valid). /// public BsonNull AsBsonNull { get { return (BsonNull)this; } } /// /// Casts the BsonValue to a BsonRegularExpression (throws an InvalidCastException if the cast is not valid). /// public BsonRegularExpression AsBsonRegularExpression { get { return (BsonRegularExpression)this; } } /// /// Casts the BsonValue to a BsonSymbol (throws an InvalidCastException if the cast is not valid). /// public BsonSymbol AsBsonSymbol { get { return (BsonSymbol)this; } } /// /// Casts the BsonValue to a BsonTimestamp (throws an InvalidCastException if the cast is not valid). /// public BsonTimestamp AsBsonTimestamp { get { return (BsonTimestamp)this; } } /// /// Casts the BsonValue to a BsonUndefined (throws an InvalidCastException if the cast is not valid). /// public BsonUndefined AsBsonUndefined { get { return (BsonUndefined)this; } } /// /// Casts the BsonValue to a BsonValue (a way of upcasting subclasses of BsonValue to BsonValue at compile time). /// public BsonValue AsBsonValue { get { return this; } } /// /// Casts the BsonValue to a Byte[] (throws an InvalidCastException if the cast is not valid). /// public byte[] AsByteArray { get { return ((BsonBinaryData)this).Bytes; } } /// /// Casts the BsonValue to a DateTime in UTC (throws an InvalidCastException if the cast is not valid). /// [Obsolete("Use ToUniversalTime instead.")] public DateTime AsDateTime { get { return AsUniversalTime; } } /// /// Casts the BsonValue to a Double (throws an InvalidCastException if the cast is not valid). /// public double AsDouble { get { return ((BsonDouble)this).Value; } } /// /// Casts the BsonValue to a Guid (throws an InvalidCastException if the cast is not valid). /// public Guid AsGuid { get { return ((BsonBinaryData)this).ToGuid(); } } /// /// Casts the BsonValue to an Int32 (throws an InvalidCastException if the cast is not valid). /// public int AsInt32 { get { return ((BsonInt32)this).Value; } } /// /// Casts the BsonValue to a DateTime in the local timezone (throws an InvalidCastException if the cast is not valid). /// [Obsolete("Use ToLocalTime instead.")] public DateTime AsLocalTime { get { return ((BsonDateTime)this).ToLocalTime(); } } /// /// Casts the BsonValue to a Int64 (throws an InvalidCastException if the cast is not valid). /// public long AsInt64 { get { return ((BsonInt64)this).Value; } } /// /// Casts the BsonValue to a Nullable{Boolean} (throws an InvalidCastException if the cast is not valid). /// public bool? AsNullableBoolean { get { return (_bsonType == BsonType.Null) ? null : (bool?)AsBoolean; } } /// /// Casts the BsonValue to a Nullable{DateTime} (throws an InvalidCastException if the cast is not valid). /// [Obsolete("Use ToNullableUniversalTime instead.")] public DateTime? AsNullableDateTime { get { return (_bsonType == BsonType.Null) ? null : (DateTime?)AsDateTime; } } /// /// Casts the BsonValue to a Nullable{Double} (throws an InvalidCastException if the cast is not valid). /// public double? AsNullableDouble { get { return (_bsonType == BsonType.Null) ? null : (double?)AsDouble; } } /// /// Casts the BsonValue to a Nullable{Guid} (throws an InvalidCastException if the cast is not valid). /// public Guid? AsNullableGuid { get { return (_bsonType == BsonType.Null) ? null : (Guid?)AsGuid; } } /// /// Casts the BsonValue to a Nullable{Int32} (throws an InvalidCastException if the cast is not valid). /// public int? AsNullableInt32 { get { return (_bsonType == BsonType.Null) ? null : (int?)AsInt32; } } /// /// Casts the BsonValue to a Nullable{Int64} (throws an InvalidCastException if the cast is not valid). /// public long? AsNullableInt64 { get { return (_bsonType == BsonType.Null) ? null : (long?)AsInt64; } } /// /// Casts the BsonValue to a Nullable{ObjectId} (throws an InvalidCastException if the cast is not valid). /// public ObjectId? AsNullableObjectId { get { return (_bsonType == BsonType.Null) ? null : (ObjectId?)AsObjectId; } } /// /// Casts the BsonValue to an ObjectId (throws an InvalidCastException if the cast is not valid). /// public ObjectId AsObjectId { get { return ((BsonObjectId)this).Value; } } /// /// Casts the BsonValue to a Regex (throws an InvalidCastException if the cast is not valid). /// public Regex AsRegex { get { return ((BsonRegularExpression)this).ToRegex(); } } /// /// Casts the BsonValue to a String (throws an InvalidCastException if the cast is not valid). /// public string AsString { get { return ((BsonString)this).Value; } } /// /// Casts the BsonValue to a DateTime in UTC (throws an InvalidCastException if the cast is not valid). /// [Obsolete("Use ToUniversalTime instead.")] public DateTime AsUniversalTime { get { return ((BsonDateTime)this).ToUniversalTime(); } } /// /// Gets the BsonType of this BsonValue. /// public BsonType BsonType { get { return _bsonType; } } /// /// Tests whether this BsonValue is a Boolean. /// public bool IsBoolean { get { return _bsonType == BsonType.Boolean; } } /// /// Tests whether this BsonValue is a BsonArray. /// public bool IsBsonArray { get { return _bsonType == BsonType.Array; } } /// /// Tests whether this BsonValue is a BsonBinaryData. /// public bool IsBsonBinaryData { get { return _bsonType == BsonType.Binary; } } /// /// Tests whether this BsonValue is a BsonDateTime. /// public bool IsBsonDateTime { get { return _bsonType == BsonType.DateTime; } } /// /// Tests whether this BsonValue is a BsonDocument. /// public bool IsBsonDocument { get { return _bsonType == BsonType.Document; } } /// /// Tests whether this BsonValue is a BsonJavaScript. /// public bool IsBsonJavaScript { get { return _bsonType == BsonType.JavaScript || _bsonType == BsonType.JavaScriptWithScope; } } /// /// Tests whether this BsonValue is a BsonJavaScriptWithScope. /// public bool IsBsonJavaScriptWithScope { get { return _bsonType == BsonType.JavaScriptWithScope; } } /// /// Tests whether this BsonValue is a BsonMaxKey. /// public bool IsBsonMaxKey { get { return _bsonType == BsonType.MaxKey; } } /// /// Tests whether this BsonValue is a BsonMinKey. /// public bool IsBsonMinKey { get { return _bsonType == BsonType.MinKey; } } /// /// Tests whether this BsonValue is a BsonNull. /// public bool IsBsonNull { get { return _bsonType == BsonType.Null; } } /// /// Tests whether this BsonValue is a BsonRegularExpression. /// public bool IsBsonRegularExpression { get { return _bsonType == BsonType.RegularExpression; } } /// /// Tests whether this BsonValue is a BsonSymbol . /// public bool IsBsonSymbol { get { return _bsonType == BsonType.Symbol; } } /// /// Tests whether this BsonValue is a BsonTimestamp. /// public bool IsBsonTimestamp { get { return _bsonType == BsonType.Timestamp; } } /// /// Tests whether this BsonValue is a BsonUndefined. /// public bool IsBsonUndefined { get { return _bsonType == BsonType.Undefined; } } /// /// Tests whether this BsonValue is a DateTime. /// [Obsolete("Use IsValidDateTime instead.")] public bool IsDateTime { get { return IsValidDateTime; } } /// /// Tests whether this BsonValue is a Double. /// public bool IsDouble { get { return _bsonType == BsonType.Double; } } /// /// Tests whether this BsonValue is a Guid. /// public bool IsGuid { get { if (_bsonType == BsonType.Binary) { var subType = ((BsonBinaryData)this).SubType; return subType == BsonBinarySubType.UuidStandard || subType == BsonBinarySubType.UuidLegacy; } else { return false; } } } /// /// Tests whether this BsonValue is an Int32. /// public bool IsInt32 { get { return _bsonType == BsonType.Int32; } } /// /// Tests whether this BsonValue is an Int64. /// public bool IsInt64 { get { return _bsonType == BsonType.Int64; } } /// /// Tests whether this BsonValue is a numeric value. /// public bool IsNumeric { get { return _bsonType == BsonType.Double || _bsonType == BsonType.Int32 || _bsonType == BsonType.Int64; } } /// /// Tests whether this BsonValue is an ObjectId . /// public bool IsObjectId { get { return _bsonType == BsonType.ObjectId; } } /// /// Tests whether this BsonValue is a String. /// public bool IsString { get { return _bsonType == BsonType.String; } } /// /// Tests whether this BsonValue is a valid DateTime. /// public virtual bool IsValidDateTime { get { return false; } } /// /// Gets the raw value of this BsonValue (or null if this BsonValue doesn't have a single scalar value). /// // note: don't change return value to "this" or lots of things will break [Obsolete("Use Value property of subclasses or BsonTypeMapper.MapToDotNetValue instead.")] public virtual object RawValue { get { return null; } // subclasses that have a single value (e.g. Int32) override this } // public operators /// /// Casts a BsonValue to a bool. /// /// The BsonValue. /// A bool. public static explicit operator bool(BsonValue value) { if (value == null) { throw new ArgumentNullException("value"); } return value.AsBoolean; } /// /// Casts a BsonValue to a bool?. /// /// The BsonValue. /// A bool?. public static explicit operator bool?(BsonValue value) { return (value == null) ? null : value.AsNullableBoolean; } /// /// Converts a bool to a BsonValue. /// /// A bool. /// A BsonValue. public static implicit operator BsonValue(bool value) { return value ? BsonBoolean.True : BsonBoolean.False; } /// /// Converts a bool? to a BsonValue. /// /// A bool?. /// A BsonValue. public static implicit operator BsonValue(bool? value) { return value.HasValue ? (BsonValue)(value.Value ? BsonBoolean.True : BsonBoolean.False) : BsonNull.Value; } /// /// Converts a byte[] to a BsonValue. /// /// A byte[]. /// A BsonValue. public static implicit operator BsonValue(byte[] value) { return (value != null) ? (BsonValue)new BsonBinaryData(value) : null; } /// /// Converts a DateTime to a BsonValue. /// /// A DateTime. /// A BsonValue. public static implicit operator BsonValue(DateTime value) { return new BsonDateTime(value); } /// /// Converts a DateTime? to a BsonValue. /// /// A DateTime?. /// A BsonValue. public static implicit operator BsonValue(DateTime? value) { return value.HasValue ? (BsonValue)new BsonDateTime(value.Value) : BsonNull.Value; } /// /// Converts a double to a BsonValue. /// /// A double. /// A BsonValue. public static implicit operator BsonValue(double value) { return new BsonDouble(value); } /// /// Converts a double? to a BsonValue. /// /// A double?. /// A BsonValue. public static implicit operator BsonValue(double? value) { return value.HasValue ? (BsonValue)new BsonDouble(value.Value) : BsonNull.Value; } /// /// Converts an Enum to a BsonValue. /// /// An Enum. /// A BsonValue. public static implicit operator BsonValue(Enum value) { return BsonTypeMapper.MapToBsonValue(value); } /// /// Converts a Guid to a BsonValue. /// /// A Guid. /// A BsonValue. public static implicit operator BsonValue(Guid value) { return new BsonBinaryData(value); } /// /// Converts a Guid? to a BsonValue. /// /// A Guid?. /// A BsonValue. public static implicit operator BsonValue(Guid? value) { return value.HasValue ? (BsonValue)new BsonBinaryData(value.Value) : BsonNull.Value; } /// /// Converts an int to a BsonValue. /// /// An int. /// A BsonValue. public static implicit operator BsonValue(int value) { return new BsonInt32(value); } /// /// Converts an int? to a BsonValue. /// /// An int?. /// A BsonValue. public static implicit operator BsonValue(int? value) { return value.HasValue ? (BsonValue)new BsonInt32(value.Value) : BsonNull.Value; } /// /// Converts a long to a BsonValue. /// /// A long. /// A BsonValue. public static implicit operator BsonValue(long value) { return new BsonInt64(value); } /// /// Converts a long? to a BsonValue. /// /// A long?. /// A BsonValue. public static implicit operator BsonValue(long? value) { return value.HasValue ? (BsonValue)new BsonInt64(value.Value) : BsonNull.Value; } /// /// Converts an ObjectId to a BsonValue. /// /// An ObjectId. /// A BsonValue. public static implicit operator BsonValue(ObjectId value) { return new BsonObjectId(value); } /// /// Converts an ObjectId? to a BsonValue. /// /// An ObjectId?. /// A BsonValue. public static implicit operator BsonValue(ObjectId? value) { return value.HasValue ? (BsonValue)new BsonObjectId(value.Value) : BsonNull.Value; } /// /// Converts a Regex to a BsonValue. /// /// A Regex. /// A BsonValue. public static implicit operator BsonValue(Regex value) { return (value != null) ? (BsonValue)new BsonRegularExpression(value) : null; } /// /// Converts a string to a BsonValue. /// /// A string. /// A BsonValue. public static implicit operator BsonValue(string value) { return (value != null) ? (BsonValue)new BsonString(value) : null; } /// /// Casts a BsonValue to a byte[]. /// /// The BsonValue. /// A byte[]. public static explicit operator byte[](BsonValue value) { return (value == null) ? null : value.AsByteArray; } /// /// Casts a BsonValue to a DateTime. /// /// The BsonValue. /// A DateTime. public static explicit operator DateTime(BsonValue value) { if (value == null) { throw new ArgumentNullException("value"); } if (!(value is BsonDateTime)) { throw new InvalidCastException(); } return value.ToUniversalTime(); } /// /// Casts a BsonValue to a DateTime?. /// /// The BsonValue. /// A DateTime?. public static explicit operator DateTime?(BsonValue value) { if (value != null && !((value is BsonDateTime) || (value is BsonNull))) { throw new InvalidCastException(); } return (value == null) ? null : value.ToNullableUniversalTime(); } /// /// Casts a BsonValue to a double. /// /// The BsonValue. /// A double. public static explicit operator double(BsonValue value) { if (value == null) { throw new ArgumentNullException("value"); } return value.AsDouble; } /// /// Casts a BsonValue to a double?. /// /// The BsonValue. /// A double?. public static explicit operator double?(BsonValue value) { return (value == null) ? null : value.AsNullableDouble; } /// /// Casts a BsonValue to a Guid. /// /// The BsonValue. /// A Guid. public static explicit operator Guid(BsonValue value) { if (value == null) { throw new ArgumentNullException("value"); } return value.AsGuid; } /// /// Casts a BsonValue to a Guid?. /// /// The BsonValue. /// A Guid?. public static explicit operator Guid?(BsonValue value) { return (value == null) ? null : value.AsNullableGuid; } /// /// Casts a BsonValue to an int. /// /// The BsonValue. /// An int. public static explicit operator int(BsonValue value) { if (value == null) { throw new ArgumentNullException("value"); } return value.AsInt32; } /// /// Casts a BsonValue to an int?. /// /// The BsonValue. /// An int?. public static explicit operator int?(BsonValue value) { return value == null ? null : value.AsNullableInt32; } /// /// Casts a BsonValue to a long. /// /// The BsonValue. /// A long. public static explicit operator long(BsonValue value) { if (value == null) { throw new ArgumentNullException("value"); } return value.AsInt64; } /// /// Casts a BsonValue to a long?. /// /// The BsonValue. /// A long?. public static explicit operator long?(BsonValue value) { return (value == null) ? null : value.AsNullableInt64; } /// /// Casts a BsonValue to an ObjectId. /// /// The BsonValue. /// An ObjectId. public static explicit operator ObjectId(BsonValue value) { if (value == null) { throw new ArgumentNullException("value"); } return value.AsObjectId; } /// /// Casts a BsonValue to an ObjectId?. /// /// The BsonValue. /// An ObjectId?. public static explicit operator ObjectId?(BsonValue value) { return (value == null) ? null : value.AsNullableObjectId; } /// /// Casts a BsonValue to a Regex. /// /// The BsonValue. /// A Regex. public static explicit operator Regex(BsonValue value) { return (value == null) ? null : value.AsRegex; } /// /// Casts a BsonValue to a string. /// /// The BsonValue. /// A string. public static explicit operator string(BsonValue value) { return (value == null) ? null : value.AsString; } /// /// Compares two BsonValues. /// /// The first BsonValue. /// The other BsonValue. /// True if the first BsonValue is less than the other one. public static bool operator <(BsonValue lhs, BsonValue rhs) { if (object.ReferenceEquals(lhs, null) && object.ReferenceEquals(rhs, null)) { return false; } if (object.ReferenceEquals(lhs, null)) { return true; } if (object.ReferenceEquals(rhs, null)) { return false; } return lhs.CompareTo(rhs) < 0; } /// /// Compares two BsonValues. /// /// The first BsonValue. /// The other BsonValue. /// True if the first BsonValue is less than or equal to the other one. public static bool operator <=(BsonValue lhs, BsonValue rhs) { if (object.ReferenceEquals(lhs, null) && object.ReferenceEquals(rhs, null)) { return true; } if (object.ReferenceEquals(lhs, null)) { return true; } if (object.ReferenceEquals(rhs, null)) { return false; } return lhs.CompareTo(rhs) <= 0; } /// /// Compares two BsonValues. /// /// The first BsonValue. /// The other BsonValue. /// True if the two BsonValues are not equal according to ==. public static bool operator !=(BsonValue lhs, BsonValue rhs) { return !(lhs == rhs); } /// /// Compares two BsonValues. /// /// The first BsonValue. /// The other BsonValue. /// True if the two BsonValues are equal according to ==. public static bool operator ==(BsonValue lhs, BsonValue rhs) { if (object.ReferenceEquals(lhs, null)) { return object.ReferenceEquals(rhs, null); } if (object.ReferenceEquals(rhs, null)) { return false; } // don't check type because sometimes different types can be == return lhs.OperatorEqualsImplementation(rhs); // some subclasses override OperatorEqualsImplementation } /// /// Compares two BsonValues. /// /// The first BsonValue. /// The other BsonValue. /// True if the first BsonValue is greater than the other one. public static bool operator >(BsonValue lhs, BsonValue rhs) { return !(lhs <= rhs); } /// /// Compares two BsonValues. /// /// The first BsonValue. /// The other BsonValue. /// True if the first BsonValue is greater than or equal to the other one. public static bool operator >=(BsonValue lhs, BsonValue rhs) { return !(lhs < rhs); } // public indexers /// /// Gets or sets a value by position (only applies to BsonDocument and BsonArray). /// /// The position. /// The value. public virtual BsonValue this[int index] { get { var message = string.Format("{0} does not support indexing by position (only BsonDocument and BsonArray do).", this.GetType().Name); throw new NotSupportedException(message); } set { var message = string.Format("{0} does not support indexing by position (only BsonDocument and BsonArray do).", this.GetType().Name); throw new NotSupportedException(message); } } /// /// Gets or sets a value by name (only applies to BsonDocument). /// /// The name. /// The value. public virtual BsonValue this[string name] { get { var message = string.Format("{0} does not support indexing by name (only BsonDocument does).", this.GetType().Name); throw new NotSupportedException(message); } set { var message = string.Format("{0} does not support indexing by name (only BsonDocument does).", this.GetType().Name); throw new NotSupportedException(message); } } // public static methods // TODO: implement more Create methods for .NET types (int, string, etc...)? Not sure... already have implicit conversions /// /// Creates a new instance of the BsonValue class. /// /// A value to be mapped to a BsonValue. /// A BsonValue. public static BsonValue Create(object value) { // optimize away the call to MapToBsonValue for the most common cases if (value == null) { return null; // not BsonNull.Value to be consistent with other Create methods } else if (value is BsonValue) { return (BsonValue)value; } else if (value is int) { return new BsonInt32((int)value); } else if (value is string) { return new BsonString((string)value); } else if (value is bool) { return (BsonBoolean)((bool)value); } else if (value is DateTime) { return new BsonDateTime((DateTime)value); } else if (value is long) { return new BsonInt64((long)value); } else if (value is double) { return new BsonDouble((double)value); } else { return BsonTypeMapper.MapToBsonValue(value); } } /// /// Reads one BsonValue from a BsonReader. /// /// The reader. /// A BsonValue. [Obsolete("Use BsonSerializer.Deserialize instead.")] public static BsonValue ReadFrom(BsonReader bsonReader) { return BsonSerializer.Deserialize(bsonReader); } // public methods /// /// Creates a shallow clone of the BsonValue (see also DeepClone). /// /// A shallow clone of the BsonValue. public virtual BsonValue Clone() { return this; // subclasses override Clone if necessary } /// /// Compares this BsonValue to another BsonValue. /// /// The other BsonValue. /// A 32-bit signed integer that indicates whether this BsonValue is less than, equal to, or greather than the other BsonValue. public abstract int CompareTo(BsonValue other); /// /// Compares the type of this BsonValue to the type of another BsonValue. /// /// The other BsonValue. /// A 32-bit signed integer that indicates whether the type of this BsonValue is less than, equal to, or greather than the type of the other BsonValue. public int CompareTypeTo(BsonValue other) { if (object.ReferenceEquals(other, null)) { return 1; } return __bsonTypeSortOrder[_bsonType].CompareTo(__bsonTypeSortOrder[other._bsonType]); } /// /// Creates a deep clone of the BsonValue (see also Clone). /// /// A deep clone of the BsonValue. public virtual BsonValue DeepClone() { return this; // subclasses override DeepClone if necessary } /// /// Compares this BsonValue to another BsonValue. /// /// The other BsonValue. /// True if the two BsonValue values are equal. public bool Equals(BsonValue rhs) { return Equals((object)rhs); } /// /// Compares this BsonValue to another object. /// /// The other object. /// True if the other object is a BsonValue and equal to this one. public override bool Equals(object obj) { throw new BsonInternalException("A subclass of BsonValue did not override Equals."); } /// /// Gets the hash code. /// /// The hash code. public override int GetHashCode() { throw new BsonInternalException("A subclass of BsonValue did not override GetHashCode."); } /// /// Converts this BsonValue to a Boolean (using the JavaScript definition of truthiness). /// /// A Boolean. public virtual bool ToBoolean() { // some subclasses override as appropriate return true; // everything else is true } /// /// Converts this BsonValue to a Double. /// /// A Double. public virtual double ToDouble() { var message = string.Format("{0} does not support ToDouble.", this.GetType().Name); throw new NotSupportedException(message); } /// /// Converts this BsonValue to an Int32. /// /// An Int32. public virtual int ToInt32() { var message = string.Format("{0} does not support ToInt32.", this.GetType().Name); throw new NotSupportedException(message); } /// /// Converts this BsonValue to an Int64. /// /// An Int64. public virtual long ToInt64() { var message = string.Format("{0} does not support ToInt64.", this.GetType().Name); throw new NotSupportedException(message); } /// /// Converts this BsonValue to a DateTime in local time. /// /// A DateTime. public virtual DateTime ToLocalTime() { var message = string.Format("{0} does not support ToLocalTime.", this.GetType().Name); throw new NotSupportedException(message); } /// /// Converts this BsonValue to a DateTime? in local time. /// /// A DateTime?. public virtual DateTime? ToNullableLocalTime() { var message = string.Format("{0} does not support ToNullableLocalTime.", this.GetType().Name); throw new NotSupportedException(message); } /// /// Converts this BsonValue to a DateTime? in UTC. /// /// A DateTime?. public virtual DateTime? ToNullableUniversalTime() { var message = string.Format("{0} does not support ToNullableUniversalTime.", this.GetType().Name); throw new NotSupportedException(message); } /// /// Converts this BsonValue to a DateTime in UTC. /// /// A DateTime. public virtual DateTime ToUniversalTime() { var message = string.Format("{0} does not support ToUniversalTime.", this.GetType().Name); throw new NotSupportedException(message); } /// /// Writes the BsonValue to a BsonWriter. /// /// The writer. [Obsolete("Use BsonSerializer.Serialize instead.")] public void WriteTo(BsonWriter bsonWriter) { BsonSerializer.Serialize(bsonWriter, this); } // protected methods /// /// Implementation of operator ==. /// /// The other BsonValue. /// True if the two BsonValues are equal according to ==. protected virtual bool OperatorEqualsImplementation(BsonValue rhs) { return Equals(rhs); // default implementation of == is to call Equals } // explicit IConvertible implementation TypeCode IConvertible.GetTypeCode() { switch (_bsonType) { case BsonType.Boolean: return TypeCode.Boolean; case BsonType.DateTime: return TypeCode.DateTime; case BsonType.Double: return TypeCode.Double; case BsonType.Int32: return TypeCode.Int32; case BsonType.Int64: return TypeCode.Int64; case BsonType.String: return TypeCode.String; default: return TypeCode.Object; } } bool IConvertible.ToBoolean(IFormatProvider provider) { switch (_bsonType) { case BsonType.Boolean: return this.AsBoolean; case BsonType.Double: return Convert.ToBoolean(this.AsDouble, provider); case BsonType.Int32: return Convert.ToBoolean(this.AsInt32, provider); case BsonType.Int64: return Convert.ToBoolean(this.AsInt64, provider); case BsonType.String: return Convert.ToBoolean(this.AsString, provider); default: throw new InvalidCastException(); } } byte IConvertible.ToByte(IFormatProvider provider) { switch (_bsonType) { case BsonType.Boolean: return Convert.ToByte(this.AsBoolean, provider); case BsonType.Double: return Convert.ToByte(this.AsDouble, provider); case BsonType.Int32: return Convert.ToByte(this.AsInt32, provider); case BsonType.Int64: return Convert.ToByte(this.AsInt64, provider); case BsonType.String: return Convert.ToByte(this.AsString, provider); default: throw new InvalidCastException(); } } char IConvertible.ToChar(IFormatProvider provider) { switch (_bsonType) { case BsonType.Int32: return Convert.ToChar(this.AsInt32, provider); case BsonType.Int64: return Convert.ToChar(this.AsInt64, provider); case BsonType.String: return Convert.ToChar(this.AsString, provider); default: throw new InvalidCastException(); } } DateTime IConvertible.ToDateTime(IFormatProvider provider) { switch (_bsonType) { case BsonType.DateTime: return this.ToUniversalTime(); case BsonType.String: return Convert.ToDateTime(this.AsString, provider); default: throw new InvalidCastException(); } } decimal IConvertible.ToDecimal(IFormatProvider provider) { switch (_bsonType) { case BsonType.Boolean: return Convert.ToDecimal(this.AsBoolean, provider); case BsonType.Double: return Convert.ToDecimal(this.AsDouble, provider); case BsonType.Int32: return Convert.ToDecimal(this.AsInt32, provider); case BsonType.Int64: return Convert.ToDecimal(this.AsInt64, provider); case BsonType.String: return Convert.ToDecimal(this.AsString, provider); default: throw new InvalidCastException(); } } double IConvertible.ToDouble(IFormatProvider provider) { switch (_bsonType) { case BsonType.Boolean: return Convert.ToDouble(this.AsBoolean, provider); case BsonType.Double: return this.AsDouble; case BsonType.Int32: return Convert.ToDouble(this.AsInt32, provider); case BsonType.Int64: return Convert.ToDouble(this.AsInt64, provider); case BsonType.String: return Convert.ToDouble(this.AsString, provider); default: throw new InvalidCastException(); } } short IConvertible.ToInt16(IFormatProvider provider) { switch (_bsonType) { case BsonType.Boolean: return Convert.ToInt16(this.AsBoolean, provider); case BsonType.Double: return Convert.ToInt16(this.AsDouble, provider); case BsonType.Int32: return Convert.ToInt16(this.AsInt32, provider); case BsonType.Int64: return Convert.ToInt16(this.AsInt64, provider); case BsonType.String: return Convert.ToInt16(this.AsString, provider); default: throw new InvalidCastException(); } } int IConvertible.ToInt32(IFormatProvider provider) { switch (_bsonType) { case BsonType.Boolean: return Convert.ToInt32(this.AsBoolean, provider); case BsonType.Double: return Convert.ToInt32(this.AsDouble, provider); case BsonType.Int32: return this.AsInt32; case BsonType.Int64: return Convert.ToInt32(this.AsInt64, provider); case BsonType.String: return Convert.ToInt32(this.AsString, provider); default: throw new InvalidCastException(); } } long IConvertible.ToInt64(IFormatProvider provider) { switch (_bsonType) { case BsonType.Boolean: return Convert.ToInt64(this.AsBoolean, provider); case BsonType.Double: return Convert.ToInt64(this.AsDouble, provider); case BsonType.Int32: return Convert.ToInt64(this.AsInt32, provider); case BsonType.Int64: return this.AsInt64; case BsonType.String: return Convert.ToInt64(this.AsString, provider); default: throw new InvalidCastException(); } } sbyte IConvertible.ToSByte(IFormatProvider provider) { switch (_bsonType) { case BsonType.Boolean: return Convert.ToSByte(this.AsBoolean, provider); case BsonType.Double: return Convert.ToSByte(this.AsDouble, provider); case BsonType.Int32: return Convert.ToSByte(this.AsInt32, provider); case BsonType.Int64: return Convert.ToSByte(this.AsInt64, provider); case BsonType.String: return Convert.ToSByte(this.AsString, provider); default: throw new InvalidCastException(); } } float IConvertible.ToSingle(IFormatProvider provider) { switch (_bsonType) { case BsonType.Boolean: return Convert.ToSingle(this.AsBoolean, provider); case BsonType.Double: return Convert.ToSingle(this.AsDouble, provider); case BsonType.Int32: return Convert.ToSingle(this.AsInt32, provider); case BsonType.Int64: return Convert.ToSingle(this.AsInt64, provider); case BsonType.String: return Convert.ToSingle(this.AsString, provider); default: throw new InvalidCastException(); } } string IConvertible.ToString(IFormatProvider provider) { switch (_bsonType) { case BsonType.Boolean: return Convert.ToString(this.AsBoolean, provider); case BsonType.Double: return Convert.ToString(this.AsDouble, provider); case BsonType.Int32: return Convert.ToString(this.AsInt32, provider); case BsonType.Int64: return Convert.ToString(this.AsInt64, provider); case BsonType.ObjectId: return this.AsObjectId.ToString(); case BsonType.String: return this.AsString; default: throw new InvalidCastException(); } } object IConvertible.ToType(Type conversionType, IFormatProvider provider) { if (conversionType == typeof(object)) { return this; } switch (_bsonType) { case BsonType.Boolean: return Convert.ChangeType(this.AsBoolean, conversionType, provider); case BsonType.DateTime: return Convert.ChangeType(this.ToUniversalTime(), conversionType, provider); case BsonType.Double: return Convert.ChangeType(this.AsDouble, conversionType, provider); case BsonType.Int32: return Convert.ChangeType(this.AsInt32, conversionType, provider); case BsonType.Int64: return Convert.ChangeType(this.AsInt64, conversionType, provider); case BsonType.ObjectId: return Convert.ChangeType(this.AsObjectId, conversionType, provider); case BsonType.String: return Convert.ChangeType(this.AsString, conversionType, provider); default: throw new InvalidCastException(); } } ushort IConvertible.ToUInt16(IFormatProvider provider) { switch (_bsonType) { case BsonType.Boolean: return Convert.ToUInt16(this.AsBoolean, provider); case BsonType.Double: return Convert.ToUInt16(this.AsDouble, provider); case BsonType.Int32: return Convert.ToUInt16(this.AsInt32, provider); case BsonType.Int64: return Convert.ToUInt16(this.AsInt64, provider); case BsonType.String: return Convert.ToUInt16(this.AsString, provider); default: throw new InvalidCastException(); } } uint IConvertible.ToUInt32(IFormatProvider provider) { switch (_bsonType) { case BsonType.Boolean: return Convert.ToUInt32(this.AsBoolean, provider); case BsonType.Double: return Convert.ToUInt32(this.AsDouble, provider); case BsonType.Int32: return Convert.ToUInt16(this.AsInt32, provider); case BsonType.Int64: return Convert.ToUInt32(this.AsInt64, provider); case BsonType.String: return Convert.ToUInt32(this.AsString, provider); default: throw new InvalidCastException(); } } ulong IConvertible.ToUInt64(IFormatProvider provider) { switch (_bsonType) { case BsonType.Boolean: return Convert.ToUInt64(this.AsBoolean, provider); case BsonType.Double: return Convert.ToUInt64(this.AsDouble, provider); case BsonType.Int32: return Convert.ToUInt64(this.AsInt32, provider); case BsonType.Int64: return Convert.ToUInt16(this.AsInt64, provider); case BsonType.String: return Convert.ToUInt64(this.AsString, provider); default: throw new InvalidCastException(); } } } }