Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / System.Activities / System / Activities / Activity.cs / 1305376 / Activity.cs
//------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.Activities
{
using System;
using System.Activities.Expressions;
using System.Activities.Hosting;
using System.Activities.Runtime;
using System.Activities.Validation;
using System.Activities.XamlIntegration;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime;
using System.Threading;
using System.Windows.Markup;
using System.Xaml;
[ContentProperty("Implementation")]
public abstract class Activity
{
static int nextCacheId;
static readonly IList emptyChildren = new List(0);
static readonly IList emptyVariables = new List(0);
static readonly IList emptyArguments = new List(0);
static readonly IList emptyDelegates = new List(0);
internal static readonly ReadOnlyCollection EmptyConstraints = new ReadOnlyCollection(new Constraint[0]);
string displayName;
bool isDisplayNameSet;
int id;
RootProperties rootProperties;
IList arguments;
IList children;
IList implementationChildren;
IList importedChildren;
IList delegates;
IList implementationDelegates;
IList importedDelegates;
IList variables;
IList implementationVariables;
IList tempValidationErrors;
IList tempAutoGeneratedArguments;
Collection constraints;
Activity runtimeImplementation;
Activity rootActivity;
object thisLock;
QualifiedId qualifiedId;
// For a given cacheId this tells us whether we've called InternalCacheMetadata yet or not
CacheStates isMetadataCached;
int cacheId;
RelationshipType relationshipToParent;
Nullable isSubtreeEmpty;
int symbolCount;
// alternatives are extended through DynamicActivity, CodeActivity, and NativeActivity
protected Activity()
{
this.thisLock = new object();
}
[XamlDeferLoad(typeof(FuncDeferringLoader), typeof(Activity))]
[DefaultValue(null)]
[Browsable(false)]
[Ambient]
protected virtual Func Implementation
{
get;
set;
}
protected Collection Constraints
{
get
{
if (this.constraints == null)
{
this.constraints = new Collection();
}
return this.constraints;
}
}
protected internal int CacheId
{
get
{
return this.cacheId;
}
}
internal bool HasNonEmptySubtree
{
get
{
if (this.isSubtreeEmpty.HasValue)
{
return !this.isSubtreeEmpty.Value;
}
else
{
if (this.Children.Count > 0 || this.ImplementationChildren.Count > 0 || this.ImportedChildren.Count > 0 ||
this.Delegates.Count > 0 || this.ImplementationDelegates.Count > 0 || this.ImportedDelegates.Count > 0 ||
this.RuntimeVariables.Count > 0 || this.ImplementationVariables.Count > 0 ||
this.RuntimeArguments.Count > 0)
{
this.isSubtreeEmpty = false;
}
else
{
this.isSubtreeEmpty = true;
}
return !this.isSubtreeEmpty.Value;
}
}
}
internal int SymbolCount
{
get
{
return this.symbolCount;
}
}
internal IdSpace MemberOf
{
get;
set;
}
internal IdSpace ParentOf
{
get;
set;
}
internal QualifiedId QualifiedId
{
get
{
if (this.qualifiedId == null)
{
this.qualifiedId = new QualifiedId(this);
}
return this.qualifiedId;
}
}
internal bool SkipArgumentResolution
{
get;
set;
}
public string DisplayName
{
get
{
if (!this.isDisplayNameSet && string.IsNullOrEmpty(this.displayName))
{
this.displayName = ActivityUtilities.GetDisplayName(this);
}
return this.displayName;
}
set
{
if (value == null)
{
this.displayName = string.Empty;
}
else
{
this.displayName = value;
}
this.isDisplayNameSet = true;
}
}
public string Id
{
get
{
if (this.id == 0)
{
return null;
}
else
{
return this.QualifiedId.ToString();
}
}
}
internal bool IsExpressionRoot
{
get
{
return this.relationshipToParent == RelationshipType.ArgumentExpression;
}
}
internal bool HasStartedCachingMetadata
{
get
{
return this.isMetadataCached != CacheStates.Uncached;
}
}
internal bool IsMetadataCached
{
get
{
return this.isMetadataCached != CacheStates.Uncached;
}
}
internal bool IsRuntimeReady
{
get
{
return (this.isMetadataCached & CacheStates.RuntimeReady) == CacheStates.RuntimeReady;
}
}
internal Activity RootActivity
{
get
{
return this.rootActivity;
}
}
internal int InternalId
{
get
{
return this.id;
}
set
{
Fx.Assert(value != 0, "0 is an invalid ID");
ClearIdInfo();
this.id = value;
}
}
internal ActivityDelegate HandlerOf
{
get;
private set;
}
internal Activity Parent
{
get;
private set;
}
internal LocationReferenceEnvironment HostEnvironment
{
get
{
if (this.RootActivity != null && this.RootActivity.rootProperties != null)
{
return this.RootActivity.rootProperties.HostEnvironment;
}
return null;
}
}
internal IList RuntimeArguments
{
get
{
return this.arguments;
}
}
internal IList Children
{
get
{
return this.children;
}
}
internal IList ImplementationChildren
{
get
{
return this.implementationChildren;
}
}
internal IList ImportedChildren
{
get
{
return this.importedChildren;
}
}
internal IList Delegates
{
get
{
return this.delegates;
}
}
internal IList ImplementationDelegates
{
get
{
return this.implementationDelegates;
}
}
internal IList ImportedDelegates
{
get
{
return this.importedDelegates;
}
}
internal bool HasBeenAssociatedWithAnInstance
{
get
{
if (this.rootProperties != null)
{
return this.rootProperties.HasBeenAssociatedWithAnInstance;
}
else if (this.IsMetadataCached && this.RootActivity != null && this.RootActivity.rootProperties != null)
{
return this.RootActivity.rootProperties.HasBeenAssociatedWithAnInstance;
}
else
{
return false;
}
}
set
{
Fx.Assert(this.rootProperties != null, "This should only be called on the root and we should already be cached.");
Fx.Assert(value, "We really only let you set this to true.");
this.rootProperties.HasBeenAssociatedWithAnInstance = value;
}
}
internal Dictionary> OverloadGroups
{
get
{
Fx.Assert(this.rootProperties != null, "This should only be called on the root.");
return this.rootProperties.OverloadGroups;
}
set
{
Fx.Assert(this.rootProperties != null, "This should only be called on the root.");
this.rootProperties.OverloadGroups = value;
}
}
internal List RequiredArgumentsNotInOverloadGroups
{
get
{
Fx.Assert(this.rootProperties != null, "This should only be called on the root.");
return this.rootProperties.RequiredArgumentsNotInOverloadGroups;
}
set
{
Fx.Assert(this.rootProperties != null, "This should only be called on the root.");
this.rootProperties.RequiredArgumentsNotInOverloadGroups = value;
}
}
internal ValidationHelper.OverloadGroupEquivalenceInfo EquivalenceInfo
{
get
{
Fx.Assert(this.rootProperties != null, "This should only be called on the root.");
return this.rootProperties.EquivalenceInfo;
}
set
{
Fx.Assert(this.rootProperties != null, "This should only be called on the root.");
this.rootProperties.EquivalenceInfo = value;
}
}
internal IList RuntimeVariables
{
get
{
return this.variables;
}
}
internal IList ImplementationVariables
{
get
{
return this.implementationVariables;
}
}
internal IList RuntimeConstraints
{
get
{
return InternalGetConstraints();
}
}
internal LocationReferenceEnvironment PublicEnvironment
{
get;
set;
}
internal LocationReferenceEnvironment ImplementationEnvironment
{
get;
set;
}
internal virtual bool InternalCanInduceIdle
{
get
{
return false;
}
}
internal bool HasTempViolations
{
get
{
return (this.tempValidationErrors != null && this.tempValidationErrors.Count > 0);
}
}
internal object ThisLock
{
get
{
return this.thisLock;
}
}
internal int RequiredExtensionTypesCount
{
get
{
Fx.Assert(this.rootProperties != null, "only callable on the root");
return this.rootProperties.RequiredExtensionTypesCount;
}
}
internal int DefaultExtensionsCount
{
get
{
Fx.Assert(this.rootProperties != null, "only callable on the root");
return this.rootProperties.DefaultExtensionsCount;
}
}
internal bool GetActivityExtensionInformation(out Dictionary activityExtensionProviders, out HashSet requiredActivityExtensionTypes)
{
Fx.Assert(this.rootProperties != null, "only callable on the root");
return this.rootProperties.GetActivityExtensionInformation(out activityExtensionProviders, out requiredActivityExtensionTypes);
}
internal virtual bool IsResultArgument(RuntimeArgument argument)
{
return false;
}
internal bool CanBeScheduledBy(Activity parent)
{
// fast path if we're the sole (or first) child
if (object.ReferenceEquals(parent, this.Parent))
{
return this.relationshipToParent == RelationshipType.ImplementationChild || this.relationshipToParent == RelationshipType.Child;
}
else
{
return parent.Children.Contains(this) || parent.ImplementationChildren.Contains(this);
}
}
internal void ClearIdInfo()
{
if (this.ParentOf != null)
{
this.ParentOf.Dispose();
this.ParentOf = null;
}
this.id = 0;
this.qualifiedId = null;
}
// We use these Set methods rather than a setter on the property since
// we don't want to make it seem like setting these collections is the
// "normal" thing to do. Only OnInternalCacheMetadata implementations
// should call these methods.
internal void SetChildrenCollection(Collection children)
{
this.children = children;
}
internal void AddChild(Activity child)
{
if (this.children == null)
{
this.children = new Collection();
}
this.children.Add(child);
}
internal void SetImplementationChildrenCollection(Collection implementationChildren)
{
this.implementationChildren = implementationChildren;
}
internal void AddImplementationChild(Activity implementationChild)
{
if (this.implementationChildren == null)
{
this.implementationChildren = new Collection();
}
this.implementationChildren.Add(implementationChild);
}
internal void SetImportedChildrenCollection(Collection importedChildren)
{
this.importedChildren = importedChildren;
}
internal void AddImportedChild(Activity importedChild)
{
if (this.importedChildren == null)
{
this.importedChildren = new Collection();
}
this.importedChildren.Add(importedChild);
}
internal void SetDelegatesCollection(Collection delegates)
{
this.delegates = delegates;
}
internal void AddDelegate(ActivityDelegate activityDelegate)
{
if (this.delegates == null)
{
this.delegates = new Collection();
}
this.delegates.Add(activityDelegate);
}
internal void SetImplementationDelegatesCollection(Collection implementationDelegates)
{
this.implementationDelegates = implementationDelegates;
}
internal void AddImplementationDelegate(ActivityDelegate implementationDelegate)
{
if (this.implementationDelegates == null)
{
this.implementationDelegates = new Collection();
}
this.implementationDelegates.Add(implementationDelegate);
}
internal void SetImportedDelegatesCollection(Collection importedDelegates)
{
this.importedDelegates = importedDelegates;
}
internal void AddImportedDelegate(ActivityDelegate importedDelegate)
{
if (this.importedDelegates == null)
{
this.importedDelegates = new Collection();
}
this.importedDelegates.Add(importedDelegate);
}
internal void SetVariablesCollection(Collection variables)
{
this.variables = variables;
}
internal void AddVariable(Variable variable)
{
if (this.variables == null)
{
this.variables = new Collection();
}
this.variables.Add(variable);
}
internal void SetImplementationVariablesCollection(Collection implementationVariables)
{
this.implementationVariables = implementationVariables;
}
internal void AddImplementationVariable(Variable implementationVariable)
{
if (this.implementationVariables == null)
{
this.implementationVariables = new Collection();
}
this.implementationVariables.Add(implementationVariable);
}
internal void SetArgumentsCollection(Collection arguments, bool createEmptyBindings)
{
this.arguments = arguments;
// Arguments should always be "as bound as possible"
if (this.arguments != null && this.arguments.Count > 0)
{
for (int i = 0; i < this.arguments.Count; i++)
{
RuntimeArgument argument = this.arguments[i];
argument.SetupBinding(this, createEmptyBindings);
}
this.arguments.QuickSort(RuntimeArgument.EvaluationOrderComparer);
}
}
internal void AddArgument(RuntimeArgument argument, bool createEmptyBindings)
{
if (this.arguments == null)
{
this.arguments = new Collection();
}
argument.SetupBinding(this, createEmptyBindings);
int insertionIndex = this.arguments.BinarySearch(argument, RuntimeArgument.EvaluationOrderComparer);
if (insertionIndex < 0)
{
this.arguments.Insert(~insertionIndex, argument);
}
else
{
this.arguments.Insert(insertionIndex, argument);
}
}
internal void SetTempValidationErrorCollection(IList validationErrors)
{
this.tempValidationErrors = validationErrors;
}
internal void TransferTempValidationErrors(ref IList newList)
{
if (this.tempValidationErrors != null)
{
for (int i = 0; i < this.tempValidationErrors.Count; i++)
{
ActivityUtilities.Add(ref newList, this.tempValidationErrors[i]);
}
}
this.tempValidationErrors = null;
}
internal void AddTempValidationError(ValidationError validationError)
{
if (this.tempValidationErrors == null)
{
this.tempValidationErrors = new Collection();
}
this.tempValidationErrors.Add(validationError);
}
internal void AddTempAutoGeneratedArgument(RuntimeArgument argument)
{
if (this.tempAutoGeneratedArguments == null)
{
this.tempAutoGeneratedArguments = new Collection();
}
this.tempAutoGeneratedArguments.Add(argument);
}
internal virtual IList InternalGetConstraints()
{
if (this.constraints != null && this.constraints.Count > 0)
{
return this.constraints;
}
else
{
return Activity.EmptyConstraints;
}
}
internal static bool NullCheck(T obj)
{
return (obj == null);
}
public override string ToString()
{
return string.Format(CultureInfo.CurrentCulture, "{0}: {1}", this.Id, this.DisplayName);
}
[EditorBrowsable(EditorBrowsableState.Never)]
public bool ShouldSerializeDisplayName()
{
return this.isDisplayNameSet;
}
// subclasses are responsible for creating/disposing the necessary contexts
internal virtual void InternalAbort(ActivityInstance instance, ActivityExecutor executor, Exception terminationReason)
{
}
// subclasses are responsible for creating/disposing the necessary contexts
internal virtual void InternalExecute(ActivityInstance instance, ActivityExecutor executor, BookmarkManager bookmarkManager)
{
if (this.runtimeImplementation != null)
{
executor.ScheduleActivity(this.runtimeImplementation, instance, null, null, null);
}
}
// subclasses are responsible for creating/disposing the necessary contexts. This implementation
// covers Activity, Activity, DynamicActivity, DynamicActivity
internal virtual void InternalCancel(ActivityInstance instance, ActivityExecutor executor, BookmarkManager bookmarkManager)
{
NativeActivityContext context = executor.NativeActivityContextPool.Acquire();
try
{
context.Initialize(instance, executor, bookmarkManager);
context.Cancel();
}
finally
{
context.Dispose();
executor.NativeActivityContextPool.Release(context);
}
}
internal bool IsSingletonActivityDeclared(string name)
{
if (this.rootActivity == null || this.rootActivity.rootProperties == null)
{
return false;
}
else
{
return this.rootActivity.rootProperties.IsSingletonActivityDeclared(name);
}
}
internal void DeclareSingletonActivity(string name)
{
if (this.rootActivity != null && this.rootActivity.rootProperties != null)
{
this.rootActivity.rootProperties.DeclareSingletonActivity(name);
}
}
internal void ClearCachedInformation()
{
ClearCachedMetadata();
this.isMetadataCached = CacheStates.Uncached;
}
internal void InitializeAsRoot(LocationReferenceEnvironment hostEnvironment)
{
// We're being treated as the root of the workflow
this.Parent = null;
this.ParentOf = null;
Interlocked.CompareExchange(ref nextCacheId, 1, int.MaxValue);
this.cacheId = Interlocked.Increment(ref nextCacheId);
ClearCachedInformation();
this.MemberOf = new IdSpace();
this.rootProperties = new RootProperties();
this.rootProperties.HostEnvironment = hostEnvironment;
this.rootActivity = this;
}
internal LocationReferenceEnvironment GetParentEnvironment()
{
LocationReferenceEnvironment parentEnvironment = null;
if (this.Parent == null)
{
Fx.Assert(this.rootProperties != null, "Root properties must be available now.");
parentEnvironment = new ActivityLocationReferenceEnvironment(this.rootProperties.HostEnvironment) { InternalRoot = this };
}
else
{
switch (this.relationshipToParent)
{
case RelationshipType.ArgumentExpression:
parentEnvironment = this.Parent.PublicEnvironment.Parent;
if (parentEnvironment == null)
{
parentEnvironment = this.RootActivity.rootProperties.HostEnvironment;
}
break;
case RelationshipType.DelegateHandler:
Fx.Assert(this.HandlerOf != null, "Must have the parent delegate set");
parentEnvironment = this.HandlerOf.Environment;
break;
case RelationshipType.Child:
case RelationshipType.ImportedChild:
case RelationshipType.VariableDefault:
parentEnvironment = this.Parent.PublicEnvironment;
break;
case RelationshipType.ImplementationChild:
parentEnvironment = this.Parent.ImplementationEnvironment;
break;
}
}
return parentEnvironment;
}
internal bool InitializeRelationship(ActivityDelegate activityDelegate, ActivityCollectionType collectionType, ref IList validationErrors)
{
if (this.cacheId == activityDelegate.Owner.CacheId)
{
// This means that we already have a parent and a delegate is trying to initialize
// a relationship. Delegate handlers MUST be declared.
ActivityUtilities.Add(ref validationErrors, new ValidationError(SR.ActivityDelegateHandlersMustBeDeclarations(this.DisplayName, activityDelegate.Owner.DisplayName, this.Parent.DisplayName), false, activityDelegate.Owner));
return false;
}
if (InitializeRelationship(activityDelegate.Owner, collectionType != ActivityCollectionType.Implementation, RelationshipType.DelegateHandler, ref validationErrors))
{
this.HandlerOf = activityDelegate;
return true;
}
return false;
}
internal bool InitializeRelationship(RuntimeArgument argument, ref IList validationErrors)
{
return InitializeRelationship(argument.Owner, true, RelationshipType.ArgumentExpression, ref validationErrors);
}
internal bool InitializeRelationship(Variable variable, bool isPublic, ref IList validationErrors)
{
return InitializeRelationship(variable.Owner, isPublic, RelationshipType.VariableDefault, ref validationErrors);
}
internal bool InitializeRelationship(Activity parent, ActivityCollectionType collectionType, ref IList validationErrors)
{
RelationshipType relationshipType = RelationshipType.Child;
if (collectionType == ActivityCollectionType.Imports)
{
relationshipType = RelationshipType.ImportedChild;
}
else if (collectionType == ActivityCollectionType.Implementation)
{
relationshipType = RelationshipType.ImplementationChild;
}
return InitializeRelationship(parent, collectionType != ActivityCollectionType.Implementation, relationshipType, ref validationErrors);
}
bool InitializeRelationship(Activity parent, bool isPublic, RelationshipType relationship, ref IList validationErrors)
{
if (this.cacheId == parent.cacheId)
{
// This means that we've already encountered a parent in the tree
// Validate that it is visible.
// In order to see the activity the new parent must be
// in the implementation IdSpace of an activity which has
// a public reference to it.
Activity referenceTarget = parent.MemberOf.Owner;
if (object.ReferenceEquals(this, parent))
{
ActivityUtilities.Add(ref validationErrors, new ValidationError(SR.ActivityCannotReferenceItself(this.DisplayName), parent));
return false;
}
else if (this.Parent == null)
{
ActivityUtilities.Add(ref validationErrors, new ValidationError(SR.RootActivityCannotBeReferenced(this.DisplayName, parent.DisplayName), parent));
return false;
}
else if (referenceTarget == null)
{
ActivityUtilities.Add(ref validationErrors, new ValidationError(SR.ActivityCannotBeReferencedWithoutTarget(this.DisplayName, parent.DisplayName, this.Parent.DisplayName), parent));
return false;
}
else if (!referenceTarget.Children.Contains(this) && !referenceTarget.ImportedChildren.Contains(this))
{
ActivityUtilities.Add(ref validationErrors, new ValidationError(SR.ActivityCannotBeReferenced(this.DisplayName, parent.DisplayName, referenceTarget.DisplayName, this.Parent.DisplayName), false, parent));
return false;
}
// This is a valid reference so we want to allow
// normal processing to proceed.
return true;
}
this.Parent = parent;
this.HandlerOf = null;
this.rootActivity = parent.RootActivity;
this.cacheId = parent.cacheId;
this.isMetadataCached = CacheStates.Uncached;
ClearCachedMetadata();
this.relationshipToParent = relationship;
if (isPublic)
{
this.MemberOf = parent.MemberOf;
}
else
{
if (parent.ParentOf == null)
{
parent.ParentOf = new IdSpace(parent.MemberOf, parent.InternalId);
}
this.MemberOf = parent.ParentOf;
}
return true;
}
void ClearCachedMetadata()
{
this.symbolCount = 0;
this.arguments = null;
this.children = null;
this.implementationChildren = null;
this.importedChildren = null;
this.delegates = null;
this.implementationDelegates = null;
this.importedDelegates = null;
this.variables = null;
this.implementationVariables = null;
}
internal void InternalCacheMetadata(bool createEmptyBindings, ref IList validationErrors)
{
OnInternalCacheMetadata(createEmptyBindings);
if (this.tempAutoGeneratedArguments != null)
{
Fx.Assert(this.tempAutoGeneratedArguments.Count > 0, "We should only have a non-null value here if we generated an argument");
if (this.arguments == null)
{
this.arguments = this.tempAutoGeneratedArguments;
}
else
{
for (int i = 0; i < this.tempAutoGeneratedArguments.Count; i++)
{
this.arguments.Add(this.tempAutoGeneratedArguments[i]);
}
}
this.tempAutoGeneratedArguments = null;
}
if (this.arguments != null && this.arguments.Count > 1)
{
ActivityValidationServices.ValidateEvaluationOrder(this.arguments, this, ref this.tempValidationErrors);
}
if (this.tempValidationErrors != null)
{
if (validationErrors == null)
{
validationErrors = new List();
}
for (int i = 0; i < this.tempValidationErrors.Count; i++)
{
ValidationError validationError = this.tempValidationErrors[i];
validationError.Source = this;
validationError.Id = this.Id;
validationErrors.Add(validationError);
}
this.tempValidationErrors = null;
}
if (this.arguments == null)
{
this.arguments = emptyArguments;
}
else
{
this.symbolCount += this.arguments.Count;
}
if (this.variables == null)
{
this.variables = emptyVariables;
}
else
{
this.symbolCount += this.variables.Count;
}
if (this.implementationVariables == null)
{
this.implementationVariables = emptyVariables;
}
else
{
this.symbolCount += this.implementationVariables.Count;
}
if (this.children == null)
{
this.children = emptyChildren;
}
if (this.importedChildren == null)
{
this.importedChildren = emptyChildren;
}
if (this.implementationChildren == null)
{
this.implementationChildren = emptyChildren;
}
if (this.delegates == null)
{
this.delegates = emptyDelegates;
}
if (this.importedDelegates == null)
{
this.importedDelegates = emptyDelegates;
}
if (this.implementationDelegates == null)
{
this.implementationDelegates = emptyDelegates;
}
this.isMetadataCached = CacheStates.Partial;
}
// Note that this is relative to the type of walk we've done. If we
// skipped implementation then we can still be "Cached" even though
// we never ignored the implementation.
internal void SetCached()
{
this.isMetadataCached = CacheStates.Full;
}
internal void SetRuntimeReady()
{
this.isMetadataCached |= CacheStates.RuntimeReady;
}
internal virtual void OnInternalCacheMetadata(bool createEmptyBindings)
{
// By running CacheMetadata first we allow the user
// to set their Implementation during CacheMetadata.
ActivityMetadata metadata = new ActivityMetadata(this, GetParentEnvironment(), createEmptyBindings);
CacheMetadata(metadata);
metadata.Dispose();
if (this.Implementation != null)
{
this.runtimeImplementation = this.Implementation();
}
else
{
this.runtimeImplementation = null;
}
if (this.runtimeImplementation != null)
{
SetImplementationChildrenCollection(new Collection
{
this.runtimeImplementation
});
}
}
protected virtual void CacheMetadata(ActivityMetadata metadata)
{
ReflectedInformation information = new ReflectedInformation(this);
SetImportedChildrenCollection(information.GetChildren());
SetVariablesCollection(information.GetVariables());
SetImportedDelegatesCollection(information.GetDelegates());
SetArgumentsCollection(information.GetArguments(), metadata.CreateEmptyBindings);
}
internal void AddDefaultExtensionProvider(Func extensionProvider)
where T : class
{
Fx.Assert(extensionProvider != null, "caller must verify");
Fx.Assert(this.rootActivity != null && this.rootActivity.rootProperties != null, "need a valid root");
this.rootActivity.rootProperties.AddDefaultExtensionProvider(extensionProvider);
}
internal void RequireExtension(Type extensionType)
{
Fx.Assert(extensionType != null && !extensionType.IsValueType, "caller should verify we have a valid reference type");
Fx.Assert(this.rootActivity != null && this.rootActivity.rootProperties != null, "need a valid root");
this.rootActivity.rootProperties.RequireExtension(extensionType);
}
// information used by root activities
class RootProperties
{
List singletonActivityNames;
Dictionary activityExtensionProviders;
HashSet requiredExtensionTypes;
public RootProperties()
{
}
public bool HasBeenAssociatedWithAnInstance
{
get;
set;
}
public LocationReferenceEnvironment HostEnvironment
{
get;
set;
}
public Dictionary> OverloadGroups
{
get;
set;
}
public List RequiredArgumentsNotInOverloadGroups
{
get;
set;
}
public ValidationHelper.OverloadGroupEquivalenceInfo EquivalenceInfo
{
get;
set;
}
public int DefaultExtensionsCount
{
get
{
if (this.activityExtensionProviders != null)
{
return this.activityExtensionProviders.Count;
}
else
{
return 0;
}
}
}
public int RequiredExtensionTypesCount
{
get
{
if (this.requiredExtensionTypes != null)
{
return this.requiredExtensionTypes.Count;
}
else
{
return 0;
}
}
}
public bool GetActivityExtensionInformation(out Dictionary activityExtensionProviders, out HashSet requiredActivityExtensionTypes)
{
activityExtensionProviders = this.activityExtensionProviders;
requiredActivityExtensionTypes = this.requiredExtensionTypes;
return activityExtensionProviders != null || (requiredExtensionTypes != null && requiredExtensionTypes.Count > 0);
}
public void AddDefaultExtensionProvider(Func extensionProvider)
where T : class
{
Type key = typeof(T);
if (this.activityExtensionProviders == null)
{
this.activityExtensionProviders = new Dictionary();
}
else
{
if (this.activityExtensionProviders.ContainsKey(key))
{
return; // already have a provider of this type
}
}
this.activityExtensionProviders.Add(key, new WorkflowInstanceExtensionProvider(extensionProvider));
// if we're providing an extension that exactly matches a required type, simplify further bookkeeping
if (this.requiredExtensionTypes != null)
{
this.requiredExtensionTypes.Remove(key);
}
}
public void RequireExtension(Type extensionType)
{
// if we're providing an extension that exactly matches a required type, don't bother with further bookkeeping
if (this.activityExtensionProviders != null && this.activityExtensionProviders.ContainsKey(extensionType))
{
return;
}
if (this.requiredExtensionTypes == null)
{
this.requiredExtensionTypes = new HashSet();
}
this.requiredExtensionTypes.Add(extensionType);
}
public bool IsSingletonActivityDeclared(string name)
{
if (this.singletonActivityNames == null)
{
return false;
}
else
{
return this.singletonActivityNames.Contains(name);
}
}
public void DeclareSingletonActivity(string name)
{
if (this.singletonActivityNames == null)
{
this.singletonActivityNames = new List(1);
}
this.singletonActivityNames.Add(name);
}
}
internal class ReflectedInformation
{
Activity parent;
Collection arguments;
Collection variables;
Collection children;
Collection delegates;
static Type DictionaryArgumentHelperType = typeof(DictionaryArgumentHelper<>);
static Type OverloadGroupAttributeType = typeof(OverloadGroupAttribute);
public ReflectedInformation(Activity owner)
: this(owner, ReflectedType.All)
{
}
ReflectedInformation(Activity activity, ReflectedType reflectType)
{
this.parent = activity;
// reflect over our activity and gather relevant pieces of the system so that the developer
// doesn't need to worry about "zipping up" his model to the constructs necessary for the
// runtime to function correctly
foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(activity))
{
ArgumentDirection direction;
Type argumentType;
if ((reflectType & ReflectedType.Argument) == ReflectedType.Argument &&
ActivityUtilities.TryGetArgumentDirectionAndType(propertyDescriptor.PropertyType, out direction, out argumentType))
{
// We only do our magic for generic argument types. If the property is a non-generic
// argument type then that means the type of the RuntimeArgument should be based on
// the type of the argument bound to it. The activity author is responsible for dealing
// with these dynamic typing cases.
if (propertyDescriptor.PropertyType.IsGenericType)
{
bool isRequired = GetIsArgumentRequired(propertyDescriptor);
List overloadGroupNames = GetOverloadGroupNames(propertyDescriptor);
RuntimeArgument argument = new RuntimeArgument(propertyDescriptor.Name, argumentType, direction, isRequired, overloadGroupNames, propertyDescriptor, activity);
Add(ref this.arguments, argument);
}
}
else if ((reflectType & ReflectedType.Variable) == ReflectedType.Variable &&
ActivityUtilities.IsVariableType(propertyDescriptor.PropertyType))
{
Variable variable = propertyDescriptor.GetValue(activity) as Variable;
if (variable != null)
{
Add(ref this.variables, variable);
}
}
else if ((reflectType & ReflectedType.Child) == ReflectedType.Child &&
ActivityUtilities.IsActivityType(propertyDescriptor.PropertyType))
{
Activity workflowElement = propertyDescriptor.GetValue(activity) as Activity;
Add(ref this.children, workflowElement);
}
else if ((reflectType & ReflectedType.ActivityDelegate) == ReflectedType.ActivityDelegate &&
ActivityUtilities.IsActivityDelegateType(propertyDescriptor.PropertyType))
{
ActivityDelegate activityDelegate = propertyDescriptor.GetValue(activity) as ActivityDelegate;
Add(ref this.delegates, activityDelegate);
}
else
{
Type innerType;
bool foundMatch = false;
if ((reflectType & ReflectedType.Argument) == ReflectedType.Argument)
{
object property = propertyDescriptor.GetValue(activity);
if (property != null)
{
IList runtimeArguments = DictionaryArgumentHelper.TryGetRuntimeArguments(property, propertyDescriptor.Name);
if (runtimeArguments != null)
{
this.AddCollection(ref this.arguments, runtimeArguments);
foundMatch = true;
}
else if (ActivityUtilities.IsArgumentDictionaryType(propertyDescriptor.PropertyType, out innerType))
{
Type concreteHelperType = DictionaryArgumentHelperType.MakeGenericType(innerType);
DictionaryArgumentHelper helper = Activator.CreateInstance(concreteHelperType, new object[] { property, propertyDescriptor.Name }) as DictionaryArgumentHelper;
this.AddCollection(ref this.arguments, helper.RuntimeArguments);
foundMatch = true;
}
}
}
if (!foundMatch && ActivityUtilities.IsKnownCollectionType(propertyDescriptor.PropertyType, out innerType))
{
if ((reflectType & ReflectedType.Variable) == ReflectedType.Variable &&
ActivityUtilities.IsVariableType(innerType))
{
IEnumerable enumerable = propertyDescriptor.GetValue(activity) as IEnumerable;
AddCollection(ref this.variables, enumerable);
}
else if ((reflectType & ReflectedType.Child) == ReflectedType.Child &&
ActivityUtilities.IsActivityType(innerType, false))
{
IEnumerable enumerable = propertyDescriptor.GetValue(activity) as IEnumerable;
AddCollection(ref this.children, enumerable);
}
else if ((reflectType & ReflectedType.ActivityDelegate) == ReflectedType.ActivityDelegate &&
ActivityUtilities.IsActivityDelegateType(innerType))
{
IEnumerable enumerable = propertyDescriptor.GetValue(activity) as IEnumerable;
AddCollection(ref this.delegates, enumerable);
}
}
}
}
}
public static Collection GetArguments(Activity parent)
{
Collection arguments = null;
if (parent != null)
{
arguments = new ReflectedInformation(parent, ReflectedType.Argument).GetArguments();
}
if (arguments == null)
{
arguments = new Collection();
}
return arguments;
}
public static Collection GetVariables(Activity parent)
{
Collection variables = null;
if (parent != null)
{
variables = new ReflectedInformation(parent, ReflectedType.Variable).GetVariables();
}
if (variables == null)
{
variables = new Collection();
}
return variables;
}
public static Collection GetChildren(Activity parent)
{
Collection children = null;
if (parent != null)
{
children = new ReflectedInformation(parent, ReflectedType.Child).GetChildren();
}
if (children == null)
{
children = new Collection();
}
return children;
}
public static Collection GetDelegates(Activity parent)
{
Collection delegates = null;
if (parent != null)
{
delegates = new ReflectedInformation(parent, ReflectedType.ActivityDelegate).GetDelegates();
}
if (delegates == null)
{
delegates = new Collection();
}
return delegates;
}
public Collection GetArguments()
{
return this.arguments;
}
public Collection GetVariables()
{
return this.variables;
}
public Collection GetChildren()
{
return this.children;
}
public Collection GetDelegates()
{
return this.delegates;
}
void AddCollection(ref Collection list, IEnumerable enumerable)
where T : class
{
if (enumerable != null)
{
foreach (object obj in enumerable)
{
if (obj != null && obj is T)
{
Add(ref list, (T)obj);
}
}
}
}
void Add(ref Collection list, T data)
{
if (data != null)
{
if (list == null)
{
list = new Collection();
}
list.Add(data);
}
}
bool GetIsArgumentRequired(PropertyDescriptor propertyDescriptor)
{
return propertyDescriptor.Attributes[typeof(RequiredArgumentAttribute)] != null;
}
List GetOverloadGroupNames(PropertyDescriptor propertyDescriptor)
{
List overloadGroupNames = new List(0);
AttributeCollection propertyAttributes = propertyDescriptor.Attributes;
for (int i = 0; i < propertyAttributes.Count; i++)
{
Attribute attribute = propertyAttributes[i];
if (ReflectedInformation.OverloadGroupAttributeType.IsAssignableFrom(attribute.GetType()))
{
overloadGroupNames.Add(((OverloadGroupAttribute)attribute).GroupName);
}
}
return overloadGroupNames;
}
[Flags]
enum ReflectedType
{
Argument = 0X1,
Variable = 0X2,
Child = 0X4,
ActivityDelegate = 0X8,
All = 0XF
}
class DictionaryArgumentHelper
{
protected DictionaryArgumentHelper()
{
}
public IList RuntimeArguments
{
get;
protected set;
}
public static IList TryGetRuntimeArguments(object propertyValue, string propertyName)
{
// special case each of the non-generic argument types to avoid reflection costs
IEnumerable> argumentEnumerable = propertyValue as IEnumerable>;
if (argumentEnumerable != null)
{
return GetRuntimeArguments(argumentEnumerable, propertyName);
}
IEnumerable> inArgumentEnumerable = propertyValue as IEnumerable>;
if (inArgumentEnumerable != null)
{
return GetRuntimeArguments(inArgumentEnumerable, propertyName);
}
IEnumerable> outArgumentEnumerable = propertyValue as IEnumerable>;
if (outArgumentEnumerable != null)
{
return GetRuntimeArguments(outArgumentEnumerable, propertyName);
}
IEnumerable> inOutArgumentEnumerable = propertyValue as IEnumerable>;
if (inOutArgumentEnumerable != null)
{
return GetRuntimeArguments(inOutArgumentEnumerable, propertyName);
}
return null;
}
protected static IList GetRuntimeArguments(IEnumerable> argumentDictionary, string propertyName) where T : Argument
{
IList runtimeArguments = new List();
foreach (KeyValuePair pair in argumentDictionary)
{
string key = pair.Key;
Argument value = pair.Value;
if (value == null)
{
string argName = (key == null) ? "" : key;
throw FxTrace.Exception.AsError(new ValidationException(SR.MissingArgument(argName, propertyName)));
}
if (string.IsNullOrEmpty(key))
{
throw FxTrace.Exception.AsError(new ValidationException(SR.MissingNameProperty(value.ArgumentType)));
}
RuntimeArgument runtimeArgument = new RuntimeArgument(key, value.ArgumentType, value.Direction, false, null, value);
runtimeArguments.Add(runtimeArgument);
}
return runtimeArguments;
}
}
class DictionaryArgumentHelper : DictionaryArgumentHelper where T : Argument
{
public DictionaryArgumentHelper(object propertyValue, string propertyName)
: base()
{
IEnumerable> argumentDictionary = propertyValue as IEnumerable>;
this.RuntimeArguments = GetRuntimeArguments(argumentDictionary, propertyName);
}
}
}
enum RelationshipType : byte
{
Child = 0x00,
ImportedChild = 0x01,
ImplementationChild = 0x02,
DelegateHandler = 0x03,
ArgumentExpression = 0x04,
VariableDefault = 0x05
}
enum CacheStates : byte
{
// We don't have valid cached data
Uncached = 0x00,
// The next two states are mutually exclusive:
// The activity has its own metadata cached
Partial = 0x01,
// The activity has its own metadata cached and
// we can make use of the roll-up metadata (like
// SubtreeHasConstraints). NOTE: Full is relative
// to the type of caching that was done. Caching
// which skips implementation will mark an activity
// as full even though the implementation has not
// been cached. This is fine right now because we
// only use this to determine whether to visit a subtree
// again during validation (skips implementation)
// or at runtime (never skips implementation).
Full = 0x02,
// The next state can be ORed with the last two:
// The cached data is ready for runtime use
RuntimeReady = 0x04
}
}
[TypeConverter(typeof(ActivityWithResultConverter))]
[ValueSerializer(typeof(ActivityWithResultValueSerializer))]
public abstract class Activity : ActivityWithResult
{
// alternatives are extended through DynamicActivity, CodeActivity, and NativeActivity
protected Activity()
: base()
{
}
[DefaultValue(null)]
public new OutArgument Result
{
get;
set;
}
internal override Type InternalResultType
{
get
{
return typeof(TResult);
}
}
internal override OutArgument ResultCore
{
get
{
return this.Result;
}
set
{
this.Result = value as OutArgument;
if (this.Result == null && value != null)
{
throw FxTrace.Exception.Argument("value", SR.ResultArgumentMustBeSpecificType(typeof(TResult)));
}
}
}
public static implicit operator Activity(TResult constValue)
{
return FromValue(constValue);
}
public static implicit operator Activity(Variable variable)
{
return FromVariable(variable);
}
public static implicit operator Activity(Variable variable)
{
return FromVariable(variable);
}
public static Activity FromValue(TResult constValue)
{
return new Literal { Value = constValue };
}
public static Activity FromVariable(Variable variable)
{
if (variable == null)
{
throw FxTrace.Exception.ArgumentNull("variable");
}
if (TypeHelper.AreTypesCompatible(variable.Type, typeof(TResult)))
{
return new VariableValue { Variable = variable };
}
else
{
Type locationGenericType;
if (ActivityUtilities.IsLocationGenericType(typeof(TResult), out locationGenericType))
{
if (locationGenericType == variable.Type)
{
return (Activity)ActivityUtilities.CreateVariableReference(variable);
}
}
}
throw FxTrace.Exception.Argument("variable", SR.ConvertVariableToValueExpressionFailed(variable.GetType().FullName, typeof(Activity).FullName));
}
[SuppressMessage(FxCop.Category.Design, FxCop.Rule.ConsiderPassingBaseTypesAsParameters,
Justification = "Generic needed for type inference")]
public static Activity FromVariable(Variable variable)
{
if (variable == null)
{
throw FxTrace.Exception.ArgumentNull("variable");
}
return new VariableValue(variable);
}
internal override bool IsResultArgument(RuntimeArgument argument)
{
return object.ReferenceEquals(argument, this.ResultRuntimeArgument);
}
internal sealed override void OnInternalCacheMetadata(bool createEmptyBindings)
{
OnInternalCacheMetadataExceptResult(createEmptyBindings);
bool foundResult = false;
// This could be null at this point
IList runtimeArguments = this.RuntimeArguments;
int runtimeArgumentCount = 0;
if (runtimeArguments != null)
{
runtimeArgumentCount = runtimeArguments.Count;
for (int i = 0; i < runtimeArgumentCount; i++)
{
RuntimeArgument argument = runtimeArguments[i];
if (argument.Name == "Result")
{
foundResult = true;
if (argument.Type != typeof(TResult) || argument.Direction != ArgumentDirection.Out)
{
// The user supplied "Result" is incorrect so we
// log a violation.
AddTempValidationError(new ValidationError(SR.ResultArgumentHasRequiredTypeAndDirection(typeof(TResult), argument.Direction, argument.Type)));
}
else if (!IsBoundArgumentCorrect(argument, createEmptyBindings))
{
// The user supplied "Result" is not bound to the correct
// argument object.
AddTempValidationError(new ValidationError(SR.ResultArgumentMustBeBoundToResultProperty));
}
else
{
// The user supplied "Result" is correct so we
// cache it.
this.ResultRuntimeArgument = argument;
}
break;
}
}
}
if (!foundResult)
{
this.ResultRuntimeArgument = new RuntimeArgument("Result", typeof(TResult), ArgumentDirection.Out);
if (this.Result == null && createEmptyBindings)
{
this.Result = new OutArgument();
}
Argument.Bind(this.Result, this.ResultRuntimeArgument);
AddArgument(this.ResultRuntimeArgument, createEmptyBindings);
}
}
bool IsBoundArgumentCorrect(RuntimeArgument argument, bool createEmptyBindings)
{
if (createEmptyBindings)
{
// We must match if we've gone through
// RuntimeArgument.SetupBinding with
// createEmptyBindings == true.
return object.ReferenceEquals(argument.BoundArgument, this.Result);
}
else
{
// Otherwise, if the Result is null then
// SetupBinding has created a default
// BoundArgument which is fine. If it
// is non-null then it had better match.
return this.Result == null || object.ReferenceEquals(argument.BoundArgument, this.Result);
}
}
internal virtual void OnInternalCacheMetadataExceptResult(bool createEmptyBindings)
{
// default to Activity's behavior
base.OnInternalCacheMetadata(createEmptyBindings);
}
// optional "fast-path" for expressions that can be resolved synchronously
internal virtual bool TryGetValue(ActivityContext context, out TResult value)
{
value = default(TResult);
return false;
}
// internal helper for TryGetValue-based resolution
internal TResult ExecuteWithTryGetValue(ActivityContext context)
{
TResult value;
if (!TryGetValue(context, out value))
{
Fx.Assert("cannot use this helper if TryGetValue returns false");
}
return value;
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ImageCollectionCodeDomSerializer.cs
- SendReply.cs
- MemberCollection.cs
- DataGridBoolColumn.cs
- VirtualDirectoryMappingCollection.cs
- LineUtil.cs
- ProgressChangedEventArgs.cs
- ItemsControlAutomationPeer.cs
- AddInController.cs
- SchemaSetCompiler.cs
- TiffBitmapEncoder.cs
- TokenBasedSet.cs
- X509ChainPolicy.cs
- VirtualPathProvider.cs
- AutoGeneratedField.cs
- SecurityHeader.cs
- AutomationIdentifierGuids.cs
- DataGridViewComboBoxCell.cs
- CategoryNameCollection.cs
- DispatcherFrame.cs
- DataGridPagerStyle.cs
- ShaperBuffers.cs
- Axis.cs
- ExtendedPropertyCollection.cs
- WebControlsSection.cs
- TemplatedEditableDesignerRegion.cs
- NavigateEvent.cs
- GeometryConverter.cs
- UrlMapping.cs
- followingquery.cs
- SecureEnvironment.cs
- PropertyDescriptorGridEntry.cs
- FileUpload.cs
- LocatorPart.cs
- FormattedText.cs
- MatrixIndependentAnimationStorage.cs
- HealthMonitoringSectionHelper.cs
- RtfToXamlReader.cs
- MenuItemBindingCollection.cs
- SecurityHelper.cs
- GraphicsPath.cs
- AssemblyUtil.cs
- UserControl.cs
- GroupBoxAutomationPeer.cs
- OleDbConnectionFactory.cs
- ServiceRoute.cs
- ScriptingSectionGroup.cs
- WindowsFormsLinkLabel.cs
- EntityExpressionVisitor.cs
- BufferAllocator.cs
- ExitEventArgs.cs
- ControlPaint.cs
- DecimalFormatter.cs
- DatagridviewDisplayedBandsData.cs
- KeyConstraint.cs
- dataSvcMapFileLoader.cs
- DelegatingTypeDescriptionProvider.cs
- ConnectionStringsExpressionBuilder.cs
- ParameterBuilder.cs
- ContentPresenter.cs
- AsyncCallback.cs
- OrderedParallelQuery.cs
- PrinterResolution.cs
- PeerNameRecord.cs
- DataGridViewCellStyleEditor.cs
- XPathSingletonIterator.cs
- AuthorizationSection.cs
- SafeSystemMetrics.cs
- FontEmbeddingManager.cs
- UpdateCommand.cs
- CodeEntryPointMethod.cs
- SelfIssuedAuthRSAPKCS1SignatureDeformatter.cs
- GenericQueueSurrogate.cs
- ComplexTypeEmitter.cs
- TextElementEnumerator.cs
- QilInvokeEarlyBound.cs
- ComAdminInterfaces.cs
- ResolveNameEventArgs.cs
- XmlSchemaAnnotated.cs
- RequestDescription.cs
- CriticalExceptions.cs
- ActivityCodeDomSerializationManager.cs
- StackSpiller.cs
- ColorAnimationBase.cs
- MetafileEditor.cs
- LookupBindingPropertiesAttribute.cs
- Base64Stream.cs
- ValueTable.cs
- Matrix3DConverter.cs
- LineUtil.cs
- ThrowHelper.cs
- _ReceiveMessageOverlappedAsyncResult.cs
- HandlerFactoryWrapper.cs
- WindowsRichEdit.cs
- ModifierKeysValueSerializer.cs
- KeyNotFoundException.cs
- ProtocolsSection.cs
- XPathQueryGenerator.cs
- CancelEventArgs.cs
- StrongTypingException.cs