/* Copyright 2010-2016 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; namespace MongoDB.Bson { /// /// Represents a BSON value (this is an abstract class, see the various subclasses). /// #if NET45 [Serializable] #endif 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.Decimal128, 4 }, { 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 } }; // 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 (throws an InvalidCastException if the cast is not valid). /// public decimal AsDecimal { get { return (decimal)((BsonDecimal128)this).Value; } } /// /// Casts the BsonValue to a (throws an InvalidCastException if the cast is not valid). /// public Decimal128 AsDecimal128 { get { return ((BsonDecimal128)this).Value; } } /// /// 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{Decimal} (throws an InvalidCastException if the cast is not valid). /// public decimal? AsNullableDecimal { get { return (BsonType == BsonType.Null) ? null : (decimal?)AsDecimal128; } } /// /// Casts the BsonValue to a Nullable{Decimal128} (throws an InvalidCastException if the cast is not valid). /// public Decimal128? AsNullableDecimal128 { get { return (BsonType == BsonType.Null) ? null : (Decimal128?)AsDecimal128; } } /// /// 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 abstract BsonType BsonType { get; } /// /// 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 Decimal128. /// public bool IsDecimal128 { get { return BsonType == BsonType.Decimal128; } } /// /// 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.Decimal128 || 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 (BsonBoolean)value; } /// /// Converts a bool? to a BsonValue. /// /// A bool?. /// A BsonValue. public static implicit operator BsonValue(bool? value) { return value.HasValue ? (BsonValue)(BsonBoolean)value.Value : 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 decimal to a BsonValue. /// /// A decimal. /// A BsonValue. public static implicit operator BsonValue(decimal value) { return (BsonDecimal128)(Decimal128)value; } /// /// Converts a decimal? to a BsonValue. /// /// A decimal?. /// A BsonValue. public static implicit operator BsonValue(decimal? value) { return value.HasValue ? (BsonValue)(BsonDecimal128)(Decimal128)value.Value : BsonNull.Value; } /// /// Converts a to a BsonValue. /// /// A Decimal128. /// A BsonValue. public static implicit operator BsonValue(Decimal128 value) { return (BsonDecimal128)value; } /// /// Converts a nullable to a BsonValue. /// /// A Decimal128?. /// A BsonValue. public static implicit operator BsonValue(Decimal128? value) { return value.HasValue ? (BsonValue)(BsonDecimal128)value.Value : BsonNull.Value; } /// /// Converts a double to a BsonValue. /// /// A double. /// A BsonValue. public static implicit operator BsonValue(double value) { return (BsonDouble)value; } /// /// Converts a double? to a BsonValue. /// /// A double?. /// A BsonValue. public static implicit operator BsonValue(double? value) { return value.HasValue ? (BsonValue)(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 (BsonInt32)value; } /// /// Converts an int? to a BsonValue. /// /// An int?. /// A BsonValue. public static implicit operator BsonValue(int? value) { return value.HasValue ? (BsonValue)(BsonInt32)value.Value : BsonNull.Value; } /// /// Converts a long to a BsonValue. /// /// A long. /// A BsonValue. public static implicit operator BsonValue(long value) { return (BsonInt64)value; } /// /// Converts a long? to a BsonValue. /// /// A long?. /// A BsonValue. public static implicit operator BsonValue(long? value) { return value.HasValue ? (BsonValue)(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)(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 decimal. /// /// The BsonValue. /// A decimal. public static explicit operator decimal(BsonValue value) { if (value == null) { throw new ArgumentNullException("value"); } return value.AsDecimal; } /// /// Casts a BsonValue to a decimal?. /// /// The BsonValue. /// A decimal?. public static explicit operator decimal?(BsonValue value) { return (value == null) ? null : value.AsNullableDecimal; } /// /// Casts a BsonValue to a . /// /// The BsonValue. /// A . public static explicit operator Decimal128(BsonValue value) { if (value == null) { throw new ArgumentNullException("value"); } return value.AsDecimal128; } /// /// Casts a BsonValue to a nullable ?. /// /// The BsonValue. /// A nullable . public static explicit operator Decimal128?(BsonValue value) { return (value == null) ? null : value.AsNullableDecimal128; } /// /// 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 /// /// 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 BsonNull.Value; } else if (value is BsonValue) { return (BsonValue)value; } else if (value is int) { return (BsonInt32)(int)value; } else if (value is string) { return (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 (BsonInt64)(long)value; } else if (value is double) { return (BsonDouble)(double)value; } else { return BsonTypeMapper.MapToBsonValue(value); } } // 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 abstract override bool Equals(object obj); /// /// Gets the hash code. /// /// The hash code. public abstract override int 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 Decimal. /// /// A Decimal. public virtual decimal ToDecimal() { var message = string.Format("{0} does not support ToDecimal.", this.GetType().Name); throw new NotSupportedException(message); } /// /// Converts this BsonValue to a Decimal128. /// /// A Decimal128. public virtual Decimal128 ToDecimal128() { var message = string.Format("{0} does not support ToDecimal128.", this.GetType().Name); throw new NotSupportedException(message); } /// /// 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); } // protected methods /// /// Implementation of the IConvertible GetTypeCode method. /// /// The TypeCode. protected virtual TypeCode IConvertibleGetTypeCodeImplementation() { return TypeCode.Object; } /// /// Implementation of the IConvertible ToBoolean method. /// /// The format provider. /// A bool. protected virtual bool IConvertibleToBooleanImplementation(IFormatProvider provider) { throw new InvalidCastException(); } /// /// Implementation of the IConvertible ToByte method. /// /// The format provider. /// A byte. protected virtual byte IConvertibleToByteImplementation(IFormatProvider provider) { throw new InvalidCastException(); } /// /// Implementation of the IConvertible ToChar method. /// /// The format provider. /// A char. protected virtual char IConvertibleToCharImplementation(IFormatProvider provider) { throw new InvalidCastException(); } /// /// Implementation of the IConvertible ToDateTime method. /// /// The format provider. /// A DateTime. protected virtual DateTime IConvertibleToDateTimeImplementation(IFormatProvider provider) { throw new InvalidCastException(); } /// /// Implementation of the IConvertible ToDecimal method. /// /// The format provider. /// A decimal. protected virtual decimal IConvertibleToDecimalImplementation(IFormatProvider provider) { throw new InvalidCastException(); } /// /// Implementation of the IConvertible ToDouble method. /// /// The format provider. /// A double. protected virtual double IConvertibleToDoubleImplementation(IFormatProvider provider) { throw new InvalidCastException(); } /// /// Implementation of the IConvertible ToInt16 method. /// /// The format provider. /// A short. protected virtual short IConvertibleToInt16Implementation(IFormatProvider provider) { throw new InvalidCastException(); } /// /// Implementation of the IConvertible ToInt32 method. /// /// The format provider. /// An int. protected virtual int IConvertibleToInt32Implementation(IFormatProvider provider) { throw new InvalidCastException(); } /// /// Implementation of the IConvertible ToInt64 method. /// /// The format provider. /// A long. protected virtual long IConvertibleToInt64Implementation(IFormatProvider provider) { throw new InvalidCastException(); } /// /// Implementation of the IConvertible ToSByte method. /// /// The format provider. /// An sbyte. #pragma warning disable 3002 protected virtual sbyte IConvertibleToSByteImplementation(IFormatProvider provider) { throw new InvalidCastException(); } #pragma warning restore /// /// Implementation of the IConvertible ToSingle method. /// /// The format provider. /// A float. protected virtual float IConvertibleToSingleImplementation(IFormatProvider provider) { throw new InvalidCastException(); } /// /// Implementation of the IConvertible ToString method. /// /// The format provider. /// A string. protected virtual string IConvertibleToStringImplementation(IFormatProvider provider) { throw new InvalidCastException(); } /// /// Implementation of the IConvertible ToUInt16 method. /// /// The format provider. /// A ushort. #pragma warning disable 3002 protected virtual ushort IConvertibleToUInt16Implementation(IFormatProvider provider) { throw new InvalidCastException(); } #pragma warning restore /// /// Implementation of the IConvertible ToUInt32 method. /// /// The format provider. /// A uint. #pragma warning disable 3002 protected virtual uint IConvertibleToUInt32Implementation(IFormatProvider provider) { throw new InvalidCastException(); } #pragma warning restore /// /// Implementation of the IConvertible ToUInt64 method. /// /// The format provider. /// A ulong. #pragma warning disable 3002 protected virtual ulong IConvertibleToUInt64Implementation(IFormatProvider provider) { throw new InvalidCastException(); } #pragma warning restore /// /// 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() { return IConvertibleGetTypeCodeImplementation(); } bool IConvertible.ToBoolean(IFormatProvider provider) { return IConvertibleToBooleanImplementation(provider); } byte IConvertible.ToByte(IFormatProvider provider) { return IConvertibleToByteImplementation(provider); } char IConvertible.ToChar(IFormatProvider provider) { return IConvertibleToCharImplementation(provider); } DateTime IConvertible.ToDateTime(IFormatProvider provider) { return IConvertibleToDateTimeImplementation(provider); } decimal IConvertible.ToDecimal(IFormatProvider provider) { return IConvertibleToDecimalImplementation(provider); } double IConvertible.ToDouble(IFormatProvider provider) { return IConvertibleToDoubleImplementation(provider); } short IConvertible.ToInt16(IFormatProvider provider) { return IConvertibleToInt16Implementation(provider); } int IConvertible.ToInt32(IFormatProvider provider) { return IConvertibleToInt32Implementation(provider); } long IConvertible.ToInt64(IFormatProvider provider) { return IConvertibleToInt64Implementation(provider); } sbyte IConvertible.ToSByte(IFormatProvider provider) { return IConvertibleToSByteImplementation(provider); } float IConvertible.ToSingle(IFormatProvider provider) { return IConvertibleToSingleImplementation(provider); } string IConvertible.ToString(IFormatProvider provider) { return IConvertibleToStringImplementation(provider); } 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.Decimal128: return Convert.ChangeType(this.AsDecimal128, 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) { return IConvertibleToUInt16Implementation(provider); } uint IConvertible.ToUInt32(IFormatProvider provider) { return IConvertibleToUInt32Implementation(provider); } ulong IConvertible.ToUInt64(IFormatProvider provider) { return IConvertibleToUInt64Implementation(provider); } } }