//----------------------------------------------------------------------- // // Copyright (c) Outercurve Foundation. All rights reserved. // //----------------------------------------------------------------------- namespace DotNetOpenAuth.Messaging.Reflection { using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; /// /// A cache of instances. /// [ContractVerification(true)] internal class MessageDescriptionCollection : IEnumerable { /// /// A dictionary of reflected message types and the generated reflection information. /// private readonly Dictionary reflectedMessageTypes = new Dictionary(); /// /// Initializes a new instance of the class. /// internal MessageDescriptionCollection() { } #region IEnumerable Members /// /// Returns an enumerator that iterates through a collection. /// /// /// An object that can be used to iterate through the collection. /// public IEnumerator GetEnumerator() { return this.reflectedMessageTypes.Values.GetEnumerator(); } #endregion #region IEnumerable Members /// /// Returns an enumerator that iterates through a collection. /// /// /// An object that can be used to iterate through the collection. /// System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return this.reflectedMessageTypes.Values.GetEnumerator(); } #endregion /// /// Gets a instance prepared for the /// given message type. /// /// A type that implements . /// The protocol version of the message. /// A instance. [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "System.Diagnostics.Contracts.__ContractsRuntime.Assume(System.Boolean,System.String,System.String)", Justification = "No localization required.")] [Pure] internal MessageDescription Get(Type messageType, Version messageVersion) { Requires.NotNullSubtype(messageType, "messageType"); Requires.NotNull(messageVersion, "messageVersion"); Contract.Ensures(Contract.Result() != null); MessageTypeAndVersion key = new MessageTypeAndVersion(messageType, messageVersion); MessageDescription result; if (!this.reflectedMessageTypes.TryGetValue(key, out result)) { lock (this.reflectedMessageTypes) { if (!this.reflectedMessageTypes.TryGetValue(key, out result)) { this.reflectedMessageTypes[key] = result = new MessageDescription(messageType, messageVersion); } } } Contract.Assume(result != null, "We should never assign null values to this dictionary."); return result; } /// /// Gets a instance prepared for the /// given message type. /// /// The message for which a should be obtained. /// /// A instance. /// [Pure] internal MessageDescription Get(IMessage message) { Requires.NotNull(message, "message"); Contract.Ensures(Contract.Result() != null); return this.Get(message.GetType(), message.Version); } /// /// Gets the dictionary that provides read/write access to a message. /// /// The message. /// The dictionary. [Pure] internal MessageDictionary GetAccessor(IMessage message) { Requires.NotNull(message, "message"); return this.GetAccessor(message, false); } /// /// Gets the dictionary that provides read/write access to a message. /// /// The message. /// A value indicating whether this message dictionary will retrieve original values instead of normalized ones. /// The dictionary. [Pure] internal MessageDictionary GetAccessor(IMessage message, bool getOriginalValues) { Requires.NotNull(message, "message"); return this.Get(message).GetDictionary(message, getOriginalValues); } /// /// A struct used as the key to bundle message type and version. /// [ContractVerification(true)] private struct MessageTypeAndVersion { /// /// Backing store for the property. /// private readonly Type type; /// /// Backing store for the property. /// private readonly Version version; /// /// Initializes a new instance of the struct. /// /// Type of the message. /// The message version. internal MessageTypeAndVersion(Type messageType, Version messageVersion) { Requires.NotNull(messageType, "messageType"); Requires.NotNull(messageVersion, "messageVersion"); this.type = messageType; this.version = messageVersion; } /// /// Gets the message type. /// [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Exposes basic identity on the type.")] internal Type Type { get { return this.type; } } /// /// Gets the message version. /// [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Exposes basic identity on the type.")] internal Version Version { get { return this.version; } } /// /// Implements the operator ==. /// /// The first object to compare. /// The second object to compare. /// The result of the operator. public static bool operator ==(MessageTypeAndVersion first, MessageTypeAndVersion second) { // structs cannot be null, so this is safe return first.Equals(second); } /// /// Implements the operator !=. /// /// The first object to compare. /// The second object to compare. /// The result of the operator. public static bool operator !=(MessageTypeAndVersion first, MessageTypeAndVersion second) { // structs cannot be null, so this is safe return !first.Equals(second); } /// /// Indicates whether this instance and a specified object are equal. /// /// Another object to compare to. /// /// true if and this instance are the same type and represent the same value; otherwise, false. /// public override bool Equals(object obj) { if (obj is MessageTypeAndVersion) { MessageTypeAndVersion other = (MessageTypeAndVersion)obj; return this.type == other.type && this.version == other.version; } else { return false; } } /// /// Returns the hash code for this instance. /// /// /// A 32-bit signed integer that is the hash code for this instance. /// public override int GetHashCode() { return this.type.GetHashCode(); } } } }