//-----------------------------------------------------------------------
//
// 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();
}
}
}
}