//----------------------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- namespace System.Activities.Hosting { using System.Collections; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Runtime; [SuppressMessage(FxCop.Category.Naming, FxCop.Rule.IdentifiersShouldHaveCorrectSuffix, Justification = "Approved name")] public sealed class SymbolResolver : IDictionary { Dictionary symbols; public SymbolResolver() { this.symbols = new Dictionary(); } public int Count { get { return this.symbols.Count; } } public bool IsReadOnly { get { return false; } } public ICollection Keys { get { return this.symbols.Keys; } } public ICollection Values { get { List values = new List(this.symbols.Count); foreach (ExternalLocationReference reference in this.symbols.Values) { values.Add(reference.Value); } return values; } } public object this[string key] { get { // We don't need to do any existence checks since we want the dictionary exception to bubble up return this.symbols[key].Value; } set { // We don't need to check key for null since we want the exception to bubble up from the inner dictionary this.symbols[key] = CreateReference(key, value); } } public void Add(string key, object value) { // We don't need to check key for null since we want the exception to bubble up from the inner dictionary this.symbols.Add(key, CreateReference(key, value)); } public void Add(string key, Type type) { if (type == null) { throw FxTrace.Exception.ArgumentNull("type"); } // We don't need to check key for null since we want the exception to bubble up from the inner dictionary this.symbols.Add(key, new ExternalLocationReference(key, type, TypeHelper.GetDefaultValueForType(type))); } public void Add(string key, object value, Type type) { if (type == null) { throw FxTrace.Exception.ArgumentNull("type"); } if (!TypeHelper.AreTypesCompatible(value, type)) { throw FxTrace.Exception.Argument("value", SR.ValueMustBeAssignableToType); } // We don't need to check key for null since we want the exception to bubble up from the inner dictionary this.symbols.Add(key, new ExternalLocationReference(key, type, value)); } ExternalLocationReference CreateReference(string name, object value) { Type valueType = TypeHelper.ObjectType; if (value != null) { valueType = value.GetType(); } return new ExternalLocationReference(name, valueType, value); } public void Add(KeyValuePair item) { Add(item.Key, item.Value); } public void Clear() { this.symbols.Clear(); } public bool Contains(KeyValuePair item) { // We don't need to check key for null since we want the exception to bubble up from the inner dictionary ExternalLocationReference reference; if (this.symbols.TryGetValue(item.Key, out reference)) { return item.Value == reference.Value; } return false; } public bool ContainsKey(string key) { // We don't need to check key for null since we want the exception to bubble up from the inner dictionary return this.symbols.ContainsKey(key); } public void CopyTo(KeyValuePair[] array, int arrayIndex) { if (array == null) { throw FxTrace.Exception.ArgumentNull("array"); } if (arrayIndex < 0) { throw FxTrace.Exception.ArgumentOutOfRange("arrayIndex", arrayIndex, SR.CopyToIndexOutOfRange); } if (array.Rank > 1) { throw FxTrace.Exception.Argument("array", SR.CopyToRankMustBeOne); } if (this.symbols.Count > array.Length - arrayIndex) { throw FxTrace.Exception.Argument("array", SR.CopyToNotEnoughSpaceInArray); } foreach (KeyValuePair pair in this.symbols) { Fx.Assert(arrayIndex < array.Length, "We must have room since we validated it."); array[arrayIndex] = new KeyValuePair(pair.Key, pair.Value.Value); arrayIndex++; } } public IEnumerator> GetEnumerator() { foreach (KeyValuePair pair in this.symbols) { yield return new KeyValuePair(pair.Key, pair.Value.Value); } } internal IEnumerable> GetLocationReferenceEnumerator() { foreach (KeyValuePair pair in this.symbols) { yield return new KeyValuePair(pair.Key, pair.Value); } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public bool Remove(string key) { // We don't need to check key for null since we want the exception to bubble up from the inner dictionary return this.symbols.Remove(key); } public bool Remove(KeyValuePair item) { // We don't need to check key for null since we want the exception to bubble up from the inner dictionary ExternalLocationReference reference; if (this.symbols.TryGetValue(item.Key, out reference)) { if (reference.Value == item.Value) { this.symbols.Remove(item.Key); return true; } } return false; } public bool TryGetValue(string key, out object value) { // We don't need to check key for null since we want the exception to bubble up from the inner dictionary ExternalLocationReference reference; if (this.symbols.TryGetValue(key, out reference)) { value = reference.Value; return true; } value = null; return false; } internal bool TryGetLocationReference(string name, out LocationReference result) { ExternalLocationReference reference; if (this.symbols.TryGetValue(name, out reference)) { result = reference; return true; } result = null; return false; } internal bool IsVisible(LocationReference locationReference) { // We only check for null since string.Empty is // actually allowed. if (locationReference.Name == null) { return false; } else { ExternalLocationReference externalLocationReference; if (this.symbols.TryGetValue(locationReference.Name, out externalLocationReference)) { if (externalLocationReference.Type == locationReference.Type) { return true; } } } return false; } Location GetLocation(string name, Type type) { ExternalLocationReference reference; if (this.symbols.TryGetValue(name, out reference)) { if (reference.Type == type) { // We're the same reference return reference.Location; } } throw FxTrace.Exception.AsError(new InvalidOperationException(SR.SymbolResolverDoesNotHaveSymbol(name, type))); } public LocationReferenceEnvironment AsLocationReferenceEnvironment() { return new SymbolResolverLocationReferenceEnvironment(this); } class SymbolResolverLocationReferenceEnvironment : LocationReferenceEnvironment { SymbolResolver symbolResolver; public SymbolResolverLocationReferenceEnvironment(SymbolResolver symbolResolver) { this.symbolResolver = symbolResolver; } public override Activity Root { get { return null; } } public override bool IsVisible(LocationReference locationReference) { if (locationReference == null) { throw FxTrace.Exception.ArgumentNull("locationReference"); } return this.symbolResolver.IsVisible(locationReference); } public override bool TryGetLocationReference(string name, out LocationReference result) { if (string.IsNullOrEmpty(name)) { throw FxTrace.Exception.ArgumentNullOrEmpty("name"); } return this.symbolResolver.TryGetLocationReference(name, out result); } public override IEnumerable GetLocationReferences() { List list = new List(); foreach (ExternalLocationReference item in this.symbolResolver.symbols.Values) { list.Add(item); } return list; } } class ExternalLocationReference : LocationReference { ExternalLocation location; string name; Type type; public ExternalLocationReference(string name, Type type, object value) { this.name = name; this.type = type; this.location = new ExternalLocation(this.type, value); } public object Value { get { return this.location.Value; } } public Location Location { get { return this.location; } } protected override string NameCore { get { return this.name; } } protected override Type TypeCore { get { return this.type; } } public override Location GetLocation(ActivityContext context) { SymbolResolver resolver = context.GetExtension(); if (resolver == null) { throw FxTrace.Exception.AsError(new InvalidOperationException(SR.CanNotFindSymbolResolverInWorkflowInstanceExtensions)); } return resolver.GetLocation(this.Name, this.Type); } class ExternalLocation : Location { Type type; object value; public ExternalLocation(Type type, object value) { this.type = type; this.value = value; } public override Type LocationType { get { return this.type; } } protected override object ValueCore { get { return this.value; } set { throw FxTrace.Exception.AsError(new InvalidOperationException(SR.ExternalLocationsGetOnly)); } } } } } }