//----------------------------------------------------------------------- // // Copyright (c) Andrew Arnott. All rights reserved. // //----------------------------------------------------------------------- namespace DotNetOpenAuth.Messaging.Reflection { using System; using System.Collections.Generic; using System.Diagnostics.Contracts; /// /// A cache of instances. /// [ContractVerification(true)] internal class MessageDescriptionCollection { /// /// A dictionary of reflected message types and the generated reflection information. /// private readonly Dictionary reflectedMessageTypes = new Dictionary(); /// /// Initializes a new instance of the class. /// public MessageDescriptionCollection() { } /// /// Gets a instance prepared for the /// given message type. /// /// A type that implements . /// The protocol version of the message. /// A instance. internal MessageDescription Get(Type messageType, Version messageVersion) { Contract.Requires(messageType != null && typeof(IMessage).IsAssignableFrom(messageType)); Contract.Requires(messageVersion != null); Contract.Ensures(Contract.Result() != null); ErrorUtilities.VerifyArgumentNotNull(messageType, "messageType"); ErrorUtilities.VerifyArgumentNotNull(messageVersion, "messageVersion"); 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(key.Type, key.Version); } } } return result; } /// /// Gets a instance prepared for the /// given message type. /// /// The message for which a should be obtained. /// /// A instance. /// internal MessageDescription Get(IMessage message) { Contract.Requires(message != null); Contract.Ensures(Contract.Result() != null); ErrorUtilities.VerifyArgumentNotNull(message, "message"); return this.Get(message.GetType(), message.Version); } /// /// Gets the dictionary that provides read/write access to a message. /// /// The message. /// The dictionary. internal MessageDictionary GetAccessor(IMessage message) { Contract.Requires(message != null); ErrorUtilities.VerifyArgumentNotNull(message, "message"); return this.Get(message).GetDictionary(message); } /// /// 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) { Contract.Requires(messageType != null); Contract.Requires(messageVersion != null); ErrorUtilities.VerifyArgumentNotNull(messageType, "messageType"); ErrorUtilities.VerifyArgumentNotNull(messageVersion, "messageVersion"); this.type = messageType; this.version = messageVersion; } /// /// Gets the message type. /// internal Type Type { get { return this.type; } } /// /// Gets the message version. /// 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(); } } } }