e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
425 lines
13 KiB
C#
425 lines
13 KiB
C#
//-----------------------------------------------------------------------------
|
|
// 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<string, object>
|
|
{
|
|
Dictionary<string, ExternalLocationReference> symbols;
|
|
|
|
public SymbolResolver()
|
|
{
|
|
this.symbols = new Dictionary<string, ExternalLocationReference>();
|
|
}
|
|
|
|
public int Count
|
|
{
|
|
get { return this.symbols.Count; }
|
|
}
|
|
|
|
public bool IsReadOnly
|
|
{
|
|
get { return false; }
|
|
}
|
|
|
|
public ICollection<string> Keys
|
|
{
|
|
get { return this.symbols.Keys; }
|
|
}
|
|
|
|
public ICollection<object> Values
|
|
{
|
|
get
|
|
{
|
|
List<object> values = new List<object>(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<string, object> item)
|
|
{
|
|
Add(item.Key, item.Value);
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
this.symbols.Clear();
|
|
}
|
|
|
|
public bool Contains(KeyValuePair<string, object> 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<string, object>[] 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<string, ExternalLocationReference> pair in this.symbols)
|
|
{
|
|
Fx.Assert(arrayIndex < array.Length, "We must have room since we validated it.");
|
|
|
|
array[arrayIndex] = new KeyValuePair<string, object>(pair.Key, pair.Value.Value);
|
|
arrayIndex++;
|
|
}
|
|
}
|
|
|
|
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
|
|
{
|
|
foreach (KeyValuePair<string, ExternalLocationReference> pair in this.symbols)
|
|
{
|
|
yield return new KeyValuePair<string, object>(pair.Key, pair.Value.Value);
|
|
}
|
|
}
|
|
|
|
internal IEnumerable<KeyValuePair<string, LocationReference>> GetLocationReferenceEnumerator()
|
|
{
|
|
foreach (KeyValuePair<string, ExternalLocationReference> pair in this.symbols)
|
|
{
|
|
yield return new KeyValuePair<string, LocationReference>(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<string, object> 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<LocationReference> GetLocationReferences()
|
|
{
|
|
List<LocationReference> list = new List<LocationReference>();
|
|
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<SymbolResolver>();
|
|
|
|
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));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|