1 //----------------------------------------------------------------------------- 2 // Copyright (c) Microsoft Corporation. All rights reserved. 3 //----------------------------------------------------------------------------- 4 5 namespace System.Activities 6 { 7 using System; 8 using System.Activities.DynamicUpdate; 9 using System.Activities.Expressions; 10 using System.Activities.Hosting; 11 using System.Activities.Runtime; 12 using System.Activities.Validation; 13 using System.Activities.XamlIntegration; 14 using System.Collections; 15 using System.Collections.Generic; 16 using System.Collections.ObjectModel; 17 using System.ComponentModel; 18 using System.Diagnostics.CodeAnalysis; 19 using System.Globalization; 20 using System.Linq; 21 using System.Runtime; 22 using System.Threading; 23 using System.Windows.Markup; 24 using System.Xaml; 25 26 [ContentProperty("Implementation")] 27 public abstract class Activity 28 { 29 const string generatedArgumentPrefix = "Argument"; 30 static int nextCacheId; 31 32 static readonly IList<Activity> emptyChildren = new List<Activity>(0); 33 static readonly IList<Variable> emptyVariables = new List<Variable>(0); 34 static readonly IList<RuntimeArgument> emptyArguments = new List<RuntimeArgument>(0); 35 static readonly IList<ActivityDelegate> emptyDelegates = new List<ActivityDelegate>(0); 36 37 internal static readonly ReadOnlyCollection<Constraint> EmptyConstraints = new ReadOnlyCollection<Constraint>(new Constraint[0]); 38 39 string displayName; 40 bool isDisplayNameSet; 41 int id; 42 RootProperties rootProperties; 43 44 IList<RuntimeArgument> arguments; 45 46 IList<Activity> children; 47 IList<Activity> implementationChildren; 48 IList<Activity> importedChildren; 49 50 IList<ActivityDelegate> delegates; 51 IList<ActivityDelegate> implementationDelegates; 52 IList<ActivityDelegate> importedDelegates; 53 54 IList<Variable> variables; 55 IList<Variable> implementationVariables; 56 57 IList<ValidationError> tempValidationErrors; 58 IList<RuntimeArgument> tempAutoGeneratedArguments; 59 60 Collection<Constraint> constraints; 61 Activity runtimeImplementation; 62 63 Activity rootActivity; 64 object thisLock; 65 66 QualifiedId qualifiedId; 67 68 // For a given cacheId this tells us whether we've called InternalCacheMetadata yet or not 69 CacheStates isMetadataCached; 70 int cacheId; 71 72 RelationshipType relationshipToParent; 73 Nullable<bool> isSubtreeEmpty; 74 75 int symbolCount; 76 77 // alternatives are extended through DynamicActivity, CodeActivity, and NativeActivity Activity()78 protected Activity() 79 { 80 this.thisLock = new object(); 81 } 82 83 [TypeConverter(typeof(ImplementationVersionConverter))] 84 [DefaultValue(null)] 85 protected virtual internal Version ImplementationVersion 86 { 87 get; 88 set; 89 } 90 91 [XamlDeferLoad(typeof(FuncDeferringLoader), typeof(Activity))] 92 [DefaultValue(null)] 93 [Browsable(false)] 94 [Ambient] 95 protected virtual Func<Activity> Implementation 96 { 97 get; 98 set; 99 } 100 101 protected Collection<Constraint> Constraints 102 { 103 get 104 { 105 if (this.constraints == null) 106 { 107 this.constraints = new Collection<Constraint>(); 108 } 109 return this.constraints; 110 } 111 } 112 113 protected internal int CacheId 114 { 115 get 116 { 117 return this.cacheId; 118 } 119 } 120 121 internal RelationshipType RelationshipToParent 122 { 123 get 124 { 125 return this.relationshipToParent; 126 } 127 } 128 129 internal bool HasNonEmptySubtree 130 { 131 get 132 { 133 if (this.isSubtreeEmpty.HasValue) 134 { 135 return !this.isSubtreeEmpty.Value; 136 } 137 else 138 { 139 if (this.Children.Count > 0 || this.ImplementationChildren.Count > 0 || this.ImportedChildren.Count > 0 || 140 this.Delegates.Count > 0 || this.ImplementationDelegates.Count > 0 || this.ImportedDelegates.Count > 0 || 141 this.RuntimeVariables.Count > 0 || this.ImplementationVariables.Count > 0 || 142 this.RuntimeArguments.Count > 0) 143 { 144 this.isSubtreeEmpty = false; 145 } 146 else 147 { 148 this.isSubtreeEmpty = true; 149 } 150 return !this.isSubtreeEmpty.Value; 151 } 152 } 153 } 154 155 internal int SymbolCount 156 { 157 get 158 { 159 return this.symbolCount; 160 } 161 } 162 163 internal IdSpace MemberOf 164 { 165 get; 166 set; 167 } 168 169 internal IdSpace ParentOf 170 { 171 get; 172 set; 173 } 174 175 internal QualifiedId QualifiedId 176 { 177 get 178 { 179 if (this.qualifiedId == null) 180 { 181 this.qualifiedId = new QualifiedId(this); 182 } 183 184 return this.qualifiedId; 185 } 186 } 187 188 // This flag governs special behavior that we need to keep for back-compat on activities 189 // that implemented TryGetValue in 4.0. 190 internal bool UseOldFastPath 191 { 192 get; 193 set; 194 } 195 196 internal bool SkipArgumentResolution 197 { 198 get; 199 set; 200 } 201 202 internal bool IsFastPath 203 { 204 get 205 { 206 return this.SkipArgumentResolution && IsActivityWithResult; 207 } 208 } 209 210 internal virtual bool IsActivityWithResult 211 { 212 get 213 { 214 return false; 215 } 216 } 217 218 internal object Origin 219 { 220 get; 221 set; 222 } 223 224 public string DisplayName 225 { 226 get 227 { 228 if (!this.isDisplayNameSet && string.IsNullOrEmpty(this.displayName)) 229 { 230 this.displayName = ActivityUtilities.GetDisplayName(this); 231 } 232 233 return this.displayName; 234 } 235 set 236 { 237 if (value == null) 238 { 239 this.displayName = string.Empty; 240 } 241 else 242 { 243 this.displayName = value; 244 } 245 this.isDisplayNameSet = true; 246 } 247 } 248 249 public string Id 250 { 251 get 252 { 253 if (this.id == 0) 254 { 255 return null; 256 } 257 else 258 { 259 return this.QualifiedId.ToString(); 260 } 261 } 262 } 263 264 internal bool IsExpressionRoot 265 { 266 get 267 { 268 return this.relationshipToParent == RelationshipType.ArgumentExpression; 269 } 270 } 271 272 internal bool HasStartedCachingMetadata 273 { 274 get 275 { 276 return this.isMetadataCached != CacheStates.Uncached; 277 } 278 } 279 280 internal bool IsMetadataCached 281 { 282 get 283 { 284 return this.isMetadataCached != CacheStates.Uncached; 285 } 286 } 287 288 internal bool IsMetadataFullyCached 289 { 290 get 291 { 292 return (this.isMetadataCached & CacheStates.Full) == CacheStates.Full; 293 } 294 } 295 296 internal bool IsRuntimeReady 297 { 298 get 299 { 300 return (this.isMetadataCached & CacheStates.RuntimeReady) == CacheStates.RuntimeReady; 301 } 302 } 303 304 internal Activity RootActivity 305 { 306 get 307 { 308 return this.rootActivity; 309 } 310 } 311 312 internal int InternalId 313 { 314 get 315 { 316 return this.id; 317 } 318 set 319 { 320 Fx.Assert(value != 0, "0 is an invalid ID"); 321 ClearIdInfo(); 322 this.id = value; 323 } 324 } 325 326 internal ActivityDelegate HandlerOf 327 { 328 get; 329 private set; 330 } 331 332 internal Activity Parent 333 { 334 get; 335 private set; 336 } 337 338 internal LocationReferenceEnvironment HostEnvironment 339 { 340 get 341 { 342 if (this.RootActivity != null && this.RootActivity.rootProperties != null) 343 { 344 return this.RootActivity.rootProperties.HostEnvironment; 345 } 346 347 return null; 348 } 349 } 350 351 internal IList<RuntimeArgument> RuntimeArguments 352 { 353 get 354 { 355 return this.arguments; 356 } 357 } 358 359 internal IList<Activity> Children 360 { 361 get 362 { 363 return this.children; 364 } 365 } 366 367 internal IList<Activity> ImplementationChildren 368 { 369 get 370 { 371 return this.implementationChildren; 372 } 373 } 374 375 internal IList<Activity> ImportedChildren 376 { 377 get 378 { 379 return this.importedChildren; 380 } 381 } 382 383 internal IList<ActivityDelegate> Delegates 384 { 385 get 386 { 387 return this.delegates; 388 } 389 } 390 391 internal IList<ActivityDelegate> ImplementationDelegates 392 { 393 get 394 { 395 return this.implementationDelegates; 396 } 397 } 398 399 internal IList<ActivityDelegate> ImportedDelegates 400 { 401 get 402 { 403 return this.importedDelegates; 404 } 405 } 406 407 internal bool HasBeenAssociatedWithAnInstance 408 { 409 get 410 { 411 if (this.rootProperties != null) 412 { 413 return this.rootProperties.HasBeenAssociatedWithAnInstance; 414 } 415 else if (this.IsMetadataCached && this.RootActivity != null && this.RootActivity.rootProperties != null) 416 { 417 return this.RootActivity.rootProperties.HasBeenAssociatedWithAnInstance; 418 } 419 else 420 { 421 return false; 422 } 423 } 424 set 425 { 426 Fx.Assert(this.rootProperties != null, "This should only be called on the root and we should already be cached."); 427 Fx.Assert(value, "We really only let you set this to true."); 428 429 this.rootProperties.HasBeenAssociatedWithAnInstance = value; 430 } 431 } 432 433 internal Dictionary<string, List<RuntimeArgument>> OverloadGroups 434 { 435 get 436 { 437 Fx.Assert(this.rootProperties != null || System.Diagnostics.Debugger.IsAttached, "This should only be called on the root."); 438 return this.rootProperties.OverloadGroups; 439 } 440 set 441 { 442 Fx.Assert(this.rootProperties != null, "This should only be called on the root."); 443 this.rootProperties.OverloadGroups = value; 444 } 445 } 446 447 internal List<RuntimeArgument> RequiredArgumentsNotInOverloadGroups 448 { 449 get 450 { 451 Fx.Assert(this.rootProperties != null || System.Diagnostics.Debugger.IsAttached, "This should only be called on the root."); 452 return this.rootProperties.RequiredArgumentsNotInOverloadGroups; 453 } 454 set 455 { 456 Fx.Assert(this.rootProperties != null, "This should only be called on the root."); 457 this.rootProperties.RequiredArgumentsNotInOverloadGroups = value; 458 } 459 } 460 461 internal ValidationHelper.OverloadGroupEquivalenceInfo EquivalenceInfo 462 { 463 get 464 { 465 Fx.Assert(this.rootProperties != null || System.Diagnostics.Debugger.IsAttached, "This should only be called on the root."); 466 return this.rootProperties.EquivalenceInfo; 467 } 468 set 469 { 470 Fx.Assert(this.rootProperties != null, "This should only be called on the root."); 471 this.rootProperties.EquivalenceInfo = value; 472 } 473 } 474 475 internal IList<Variable> RuntimeVariables 476 { 477 get 478 { 479 return this.variables; 480 } 481 } 482 483 internal IList<Variable> ImplementationVariables 484 { 485 get 486 { 487 return this.implementationVariables; 488 } 489 } 490 491 internal IList<Constraint> RuntimeConstraints 492 { 493 get 494 { 495 return InternalGetConstraints(); 496 } 497 } 498 499 internal LocationReferenceEnvironment PublicEnvironment 500 { 501 get; 502 set; 503 } 504 505 internal LocationReferenceEnvironment ImplementationEnvironment 506 { 507 get; 508 set; 509 } 510 511 internal virtual bool InternalCanInduceIdle 512 { 513 get 514 { 515 return false; 516 } 517 } 518 519 internal bool HasTempViolations 520 { 521 get 522 { 523 return (this.tempValidationErrors != null && this.tempValidationErrors.Count > 0); 524 } 525 } 526 527 internal object ThisLock 528 { 529 get 530 { 531 return this.thisLock; 532 } 533 } 534 535 internal int RequiredExtensionTypesCount 536 { 537 get 538 { 539 Fx.Assert(this.rootProperties != null || System.Diagnostics.Debugger.IsAttached, "only callable on the root"); 540 return this.rootProperties.RequiredExtensionTypesCount; 541 } 542 } 543 544 internal int DefaultExtensionsCount 545 { 546 get 547 { 548 Fx.Assert(this.rootProperties != null || System.Diagnostics.Debugger.IsAttached, "only callable on the root"); 549 return this.rootProperties.DefaultExtensionsCount; 550 } 551 } 552 GetActivityExtensionInformation(out Dictionary<Type, WorkflowInstanceExtensionProvider> activityExtensionProviders, out HashSet<Type> requiredActivityExtensionTypes)553 internal bool GetActivityExtensionInformation(out Dictionary<Type, WorkflowInstanceExtensionProvider> activityExtensionProviders, out HashSet<Type> requiredActivityExtensionTypes) 554 { 555 Fx.Assert(this.rootProperties != null, "only callable on the root"); 556 return this.rootProperties.GetActivityExtensionInformation(out activityExtensionProviders, out requiredActivityExtensionTypes); 557 } 558 IsResultArgument(RuntimeArgument argument)559 internal virtual bool IsResultArgument(RuntimeArgument argument) 560 { 561 return false; 562 } 563 CanBeScheduledBy(Activity parent)564 internal bool CanBeScheduledBy(Activity parent) 565 { 566 // fast path if we're the sole (or first) child 567 if (object.ReferenceEquals(parent, this.Parent)) 568 { 569 return this.relationshipToParent == RelationshipType.ImplementationChild || this.relationshipToParent == RelationshipType.Child; 570 } 571 else 572 { 573 return parent.Children.Contains(this) || parent.ImplementationChildren.Contains(this); 574 } 575 } 576 ClearIdInfo()577 internal void ClearIdInfo() 578 { 579 if (this.ParentOf != null) 580 { 581 this.ParentOf.Dispose(); 582 this.ParentOf = null; 583 } 584 585 this.id = 0; 586 this.qualifiedId = null; 587 } 588 589 // We use these Set methods rather than a setter on the property since 590 // we don't want to make it seem like setting these collections is the 591 // "normal" thing to do. Only OnInternalCacheMetadata implementations 592 // should call these methods. SetChildrenCollection(Collection<Activity> children)593 internal void SetChildrenCollection(Collection<Activity> children) 594 { 595 this.children = children; 596 } 597 AddChild(Activity child)598 internal void AddChild(Activity child) 599 { 600 if (this.children == null) 601 { 602 this.children = new Collection<Activity>(); 603 } 604 605 this.children.Add(child); 606 } 607 SetImplementationChildrenCollection(Collection<Activity> implementationChildren)608 internal void SetImplementationChildrenCollection(Collection<Activity> implementationChildren) 609 { 610 this.implementationChildren = implementationChildren; 611 } 612 AddImplementationChild(Activity implementationChild)613 internal void AddImplementationChild(Activity implementationChild) 614 { 615 if (this.implementationChildren == null) 616 { 617 this.implementationChildren = new Collection<Activity>(); 618 } 619 620 this.implementationChildren.Add(implementationChild); 621 } 622 SetImportedChildrenCollection(Collection<Activity> importedChildren)623 internal void SetImportedChildrenCollection(Collection<Activity> importedChildren) 624 { 625 this.importedChildren = importedChildren; 626 } 627 AddImportedChild(Activity importedChild)628 internal void AddImportedChild(Activity importedChild) 629 { 630 if (this.importedChildren == null) 631 { 632 this.importedChildren = new Collection<Activity>(); 633 } 634 635 this.importedChildren.Add(importedChild); 636 } 637 SetDelegatesCollection(Collection<ActivityDelegate> delegates)638 internal void SetDelegatesCollection(Collection<ActivityDelegate> delegates) 639 { 640 this.delegates = delegates; 641 } 642 AddDelegate(ActivityDelegate activityDelegate)643 internal void AddDelegate(ActivityDelegate activityDelegate) 644 { 645 if (this.delegates == null) 646 { 647 this.delegates = new Collection<ActivityDelegate>(); 648 } 649 650 this.delegates.Add(activityDelegate); 651 } 652 SetImplementationDelegatesCollection(Collection<ActivityDelegate> implementationDelegates)653 internal void SetImplementationDelegatesCollection(Collection<ActivityDelegate> implementationDelegates) 654 { 655 this.implementationDelegates = implementationDelegates; 656 } 657 AddImplementationDelegate(ActivityDelegate implementationDelegate)658 internal void AddImplementationDelegate(ActivityDelegate implementationDelegate) 659 { 660 if (this.implementationDelegates == null) 661 { 662 this.implementationDelegates = new Collection<ActivityDelegate>(); 663 } 664 665 this.implementationDelegates.Add(implementationDelegate); 666 } 667 SetImportedDelegatesCollection(Collection<ActivityDelegate> importedDelegates)668 internal void SetImportedDelegatesCollection(Collection<ActivityDelegate> importedDelegates) 669 { 670 this.importedDelegates = importedDelegates; 671 } 672 AddImportedDelegate(ActivityDelegate importedDelegate)673 internal void AddImportedDelegate(ActivityDelegate importedDelegate) 674 { 675 if (this.importedDelegates == null) 676 { 677 this.importedDelegates = new Collection<ActivityDelegate>(); 678 } 679 680 this.importedDelegates.Add(importedDelegate); 681 } 682 SetVariablesCollection(Collection<Variable> variables)683 internal void SetVariablesCollection(Collection<Variable> variables) 684 { 685 this.variables = variables; 686 } 687 AddVariable(Variable variable)688 internal void AddVariable(Variable variable) 689 { 690 if (this.variables == null) 691 { 692 this.variables = new Collection<Variable>(); 693 } 694 695 this.variables.Add(variable); 696 } 697 SetImplementationVariablesCollection(Collection<Variable> implementationVariables)698 internal void SetImplementationVariablesCollection(Collection<Variable> implementationVariables) 699 { 700 this.implementationVariables = implementationVariables; 701 } 702 AddImplementationVariable(Variable implementationVariable)703 internal void AddImplementationVariable(Variable implementationVariable) 704 { 705 if (this.implementationVariables == null) 706 { 707 this.implementationVariables = new Collection<Variable>(); 708 } 709 710 this.implementationVariables.Add(implementationVariable); 711 } 712 SetArgumentsCollection(Collection<RuntimeArgument> arguments, bool createEmptyBindings)713 internal void SetArgumentsCollection(Collection<RuntimeArgument> arguments, bool createEmptyBindings) 714 { 715 this.arguments = arguments; 716 717 // Arguments should always be "as bound as possible" 718 if (this.arguments != null && this.arguments.Count > 0) 719 { 720 for (int i = 0; i < this.arguments.Count; i++) 721 { 722 RuntimeArgument argument = this.arguments[i]; 723 724 argument.SetupBinding(this, createEmptyBindings); 725 } 726 727 this.arguments.QuickSort(RuntimeArgument.EvaluationOrderComparer); 728 } 729 } 730 AddArgument(RuntimeArgument argument, bool createEmptyBindings)731 internal void AddArgument(RuntimeArgument argument, bool createEmptyBindings) 732 { 733 if (this.arguments == null) 734 { 735 this.arguments = new Collection<RuntimeArgument>(); 736 } 737 738 argument.SetupBinding(this, createEmptyBindings); 739 740 int insertionIndex = this.arguments.BinarySearch(argument, RuntimeArgument.EvaluationOrderComparer); 741 if (insertionIndex < 0) 742 { 743 this.arguments.Insert(~insertionIndex, argument); 744 } 745 else 746 { 747 this.arguments.Insert(insertionIndex, argument); 748 } 749 } 750 SetTempValidationErrorCollection(IList<ValidationError> validationErrors)751 internal void SetTempValidationErrorCollection(IList<ValidationError> validationErrors) 752 { 753 this.tempValidationErrors = validationErrors; 754 } 755 TransferTempValidationErrors(ref IList<ValidationError> newList)756 internal void TransferTempValidationErrors(ref IList<ValidationError> newList) 757 { 758 if (this.tempValidationErrors != null) 759 { 760 for (int i = 0; i < this.tempValidationErrors.Count; i++) 761 { 762 ActivityUtilities.Add(ref newList, this.tempValidationErrors[i]); 763 } 764 } 765 this.tempValidationErrors = null; 766 767 } 768 AddTempValidationError(ValidationError validationError)769 internal void AddTempValidationError(ValidationError validationError) 770 { 771 if (this.tempValidationErrors == null) 772 { 773 this.tempValidationErrors = new Collection<ValidationError>(); 774 } 775 776 this.tempValidationErrors.Add(validationError); 777 } 778 AddTempAutoGeneratedArgument(Type argumentType, ArgumentDirection direction)779 internal RuntimeArgument AddTempAutoGeneratedArgument(Type argumentType, ArgumentDirection direction) 780 { 781 if (this.tempAutoGeneratedArguments == null) 782 { 783 this.tempAutoGeneratedArguments = new Collection<RuntimeArgument>(); 784 } 785 786 string name = generatedArgumentPrefix + this.tempAutoGeneratedArguments.Count.ToString(CultureInfo.InvariantCulture); 787 RuntimeArgument argument = new RuntimeArgument(name, argumentType, direction); 788 this.tempAutoGeneratedArguments.Add(argument); 789 return argument; 790 } 791 ResetTempAutoGeneratedArguments()792 internal void ResetTempAutoGeneratedArguments() 793 { 794 this.tempAutoGeneratedArguments = null; 795 } 796 InternalGetConstraints()797 internal virtual IList<Constraint> InternalGetConstraints() 798 { 799 if (this.constraints != null && this.constraints.Count > 0) 800 { 801 return this.constraints; 802 } 803 else 804 { 805 return Activity.EmptyConstraints; 806 } 807 } 808 NullCheck(T obj)809 internal static bool NullCheck<T>(T obj) 810 { 811 return (obj == null); 812 } 813 ToString()814 public override string ToString() 815 { 816 return string.Format(CultureInfo.CurrentCulture, "{0}: {1}", this.Id, this.DisplayName); 817 } 818 819 [EditorBrowsable(EditorBrowsableState.Never)] ShouldSerializeDisplayName()820 public bool ShouldSerializeDisplayName() 821 { 822 return this.isDisplayNameSet; 823 } 824 825 // subclasses are responsible for creating/disposing the necessary contexts InternalAbort(ActivityInstance instance, ActivityExecutor executor, Exception terminationReason)826 internal virtual void InternalAbort(ActivityInstance instance, ActivityExecutor executor, Exception terminationReason) 827 { 828 } 829 830 // subclasses are responsible for creating/disposing the necessary contexts InternalExecute(ActivityInstance instance, ActivityExecutor executor, BookmarkManager bookmarkManager)831 internal virtual void InternalExecute(ActivityInstance instance, ActivityExecutor executor, BookmarkManager bookmarkManager) 832 { 833 if (this.runtimeImplementation != null) 834 { 835 executor.ScheduleActivity(this.runtimeImplementation, instance, null, null, null); 836 } 837 } 838 839 // subclasses are responsible for creating/disposing the necessary contexts. This implementation 840 // covers Activity, Activity<T>, DynamicActivity, DynamicActivity<T> InternalCancel(ActivityInstance instance, ActivityExecutor executor, BookmarkManager bookmarkManager)841 internal virtual void InternalCancel(ActivityInstance instance, ActivityExecutor executor, BookmarkManager bookmarkManager) 842 { 843 NativeActivityContext context = executor.NativeActivityContextPool.Acquire(); 844 try 845 { 846 context.Initialize(instance, executor, bookmarkManager); 847 context.Cancel(); 848 } 849 finally 850 { 851 context.Dispose(); 852 executor.NativeActivityContextPool.Release(context); 853 } 854 } 855 IsSingletonActivityDeclared(string name)856 internal bool IsSingletonActivityDeclared(string name) 857 { 858 if (this.rootActivity == null || this.rootActivity.rootProperties == null) 859 { 860 return false; 861 } 862 else 863 { 864 return this.rootActivity.rootProperties.IsSingletonActivityDeclared(name); 865 } 866 } 867 DeclareSingletonActivity(string name, Activity activity)868 internal void DeclareSingletonActivity(string name, Activity activity) 869 { 870 if (this.rootActivity != null && this.rootActivity.rootProperties != null) 871 { 872 this.rootActivity.rootProperties.DeclareSingletonActivity(name, activity); 873 } 874 } 875 GetSingletonActivity(string name)876 internal Activity GetSingletonActivity(string name) 877 { 878 if (this.rootActivity != null && this.rootActivity.rootProperties != null) 879 { 880 return this.rootActivity.rootProperties.GetSingletonActivity(name); 881 } 882 883 return null; 884 } 885 ClearCachedInformation()886 internal void ClearCachedInformation() 887 { 888 ClearCachedMetadata(); 889 this.isMetadataCached = CacheStates.Uncached; 890 } 891 InitializeAsRoot(LocationReferenceEnvironment hostEnvironment)892 internal void InitializeAsRoot(LocationReferenceEnvironment hostEnvironment) 893 { 894 // We're being treated as the root of the workflow 895 this.Parent = null; 896 this.ParentOf = null; 897 898 Interlocked.CompareExchange(ref nextCacheId, 1, int.MaxValue); 899 this.cacheId = Interlocked.Increment(ref nextCacheId); 900 901 ClearCachedInformation(); 902 903 this.MemberOf = new IdSpace(); 904 this.rootProperties = new RootProperties(); 905 this.rootProperties.HostEnvironment = hostEnvironment; 906 this.rootActivity = this; 907 } 908 GetParentEnvironment()909 internal LocationReferenceEnvironment GetParentEnvironment() 910 { 911 LocationReferenceEnvironment parentEnvironment = null; 912 913 if (this.Parent == null) 914 { 915 Fx.Assert(this.rootProperties != null, "Root properties must be available now."); 916 917 parentEnvironment = new ActivityLocationReferenceEnvironment(this.rootProperties.HostEnvironment) { InternalRoot = this }; 918 } 919 else 920 { 921 switch (this.relationshipToParent) 922 { 923 case RelationshipType.ArgumentExpression: 924 parentEnvironment = this.Parent.PublicEnvironment.Parent; 925 926 if (parentEnvironment == null) 927 { 928 parentEnvironment = this.RootActivity.rootProperties.HostEnvironment; 929 } 930 break; 931 case RelationshipType.DelegateHandler: 932 Fx.Assert(this.HandlerOf != null, "Must have the parent delegate set"); 933 934 parentEnvironment = this.HandlerOf.Environment; 935 break; 936 case RelationshipType.Child: 937 case RelationshipType.ImportedChild: 938 case RelationshipType.VariableDefault: 939 parentEnvironment = this.Parent.PublicEnvironment; 940 break; 941 case RelationshipType.ImplementationChild: 942 parentEnvironment = this.Parent.ImplementationEnvironment; 943 break; 944 } 945 } 946 947 return parentEnvironment; 948 } 949 InitializeRelationship(ActivityDelegate activityDelegate, ActivityCollectionType collectionType, ref IList<ValidationError> validationErrors)950 internal bool InitializeRelationship(ActivityDelegate activityDelegate, ActivityCollectionType collectionType, ref IList<ValidationError> validationErrors) 951 { 952 if (this.cacheId == activityDelegate.Owner.CacheId) 953 { 954 // This means that we already have a parent and a delegate is trying to initialize 955 // a relationship. Delegate handlers MUST be declared. 956 957 ActivityUtilities.Add(ref validationErrors, new ValidationError(SR.ActivityDelegateHandlersMustBeDeclarations(this.DisplayName, activityDelegate.Owner.DisplayName, this.Parent.DisplayName), false, activityDelegate.Owner)); 958 959 return false; 960 } 961 962 if (InitializeRelationship(activityDelegate.Owner, collectionType != ActivityCollectionType.Implementation, RelationshipType.DelegateHandler, ref validationErrors)) 963 { 964 this.HandlerOf = activityDelegate; 965 966 return true; 967 } 968 969 return false; 970 } 971 InitializeRelationship(RuntimeArgument argument, ref IList<ValidationError> validationErrors)972 internal bool InitializeRelationship(RuntimeArgument argument, ref IList<ValidationError> validationErrors) 973 { 974 return InitializeRelationship(argument.Owner, true, RelationshipType.ArgumentExpression, ref validationErrors); 975 } 976 InitializeRelationship(Variable variable, bool isPublic, ref IList<ValidationError> validationErrors)977 internal bool InitializeRelationship(Variable variable, bool isPublic, ref IList<ValidationError> validationErrors) 978 { 979 return InitializeRelationship(variable.Owner, isPublic, RelationshipType.VariableDefault, ref validationErrors); 980 } 981 InitializeRelationship(Activity parent, ActivityCollectionType collectionType, ref IList<ValidationError> validationErrors)982 internal bool InitializeRelationship(Activity parent, ActivityCollectionType collectionType, ref IList<ValidationError> validationErrors) 983 { 984 RelationshipType relationshipType = RelationshipType.Child; 985 if (collectionType == ActivityCollectionType.Imports) 986 { 987 relationshipType = RelationshipType.ImportedChild; 988 } 989 else if (collectionType == ActivityCollectionType.Implementation) 990 { 991 relationshipType = RelationshipType.ImplementationChild; 992 } 993 994 return InitializeRelationship(parent, collectionType != ActivityCollectionType.Implementation, relationshipType, ref validationErrors); 995 } 996 InitializeRelationship(Activity parent, bool isPublic, RelationshipType relationship, ref IList<ValidationError> validationErrors)997 bool InitializeRelationship(Activity parent, bool isPublic, RelationshipType relationship, ref IList<ValidationError> validationErrors) 998 { 999 if (this.cacheId == parent.cacheId) 1000 { 1001 // This means that we've already encountered a parent in the tree 1002 1003 // Validate that it is visible. 1004 1005 // In order to see the activity the new parent must be 1006 // in the implementation IdSpace of an activity which has 1007 // a public reference to it. 1008 Activity referenceTarget = parent.MemberOf.Owner; 1009 1010 if (object.ReferenceEquals(this, parent)) 1011 { 1012 ActivityUtilities.Add(ref validationErrors, new ValidationError(SR.ActivityCannotReferenceItself(this.DisplayName), parent)); 1013 1014 return false; 1015 } 1016 else if (this.Parent == null) 1017 { 1018 ActivityUtilities.Add(ref validationErrors, new ValidationError(SR.RootActivityCannotBeReferenced(this.DisplayName, parent.DisplayName), parent)); 1019 1020 return false; 1021 } 1022 else if (referenceTarget == null) 1023 { 1024 ActivityUtilities.Add(ref validationErrors, new ValidationError(SR.ActivityCannotBeReferencedWithoutTarget(this.DisplayName, parent.DisplayName, this.Parent.DisplayName), parent)); 1025 1026 return false; 1027 } 1028 else if (!referenceTarget.Children.Contains(this) && !referenceTarget.ImportedChildren.Contains(this)) 1029 { 1030 ActivityUtilities.Add(ref validationErrors, new ValidationError(SR.ActivityCannotBeReferenced(this.DisplayName, parent.DisplayName, referenceTarget.DisplayName, this.Parent.DisplayName), false, parent)); 1031 1032 return false; 1033 } 1034 1035 // This is a valid reference so we want to allow 1036 // normal processing to proceed. 1037 return true; 1038 } 1039 1040 this.Parent = parent; 1041 this.HandlerOf = null; 1042 this.rootActivity = parent.RootActivity; 1043 this.cacheId = parent.cacheId; 1044 this.isMetadataCached = CacheStates.Uncached; 1045 ClearCachedMetadata(); 1046 this.relationshipToParent = relationship; 1047 1048 if (isPublic) 1049 { 1050 this.MemberOf = parent.MemberOf; 1051 } 1052 else 1053 { 1054 if (parent.ParentOf == null) 1055 { 1056 parent.ParentOf = new IdSpace(parent.MemberOf, parent.InternalId); 1057 } 1058 1059 this.MemberOf = parent.ParentOf; 1060 } 1061 1062 return true; 1063 } 1064 ClearCachedMetadata()1065 void ClearCachedMetadata() 1066 { 1067 this.symbolCount = 0; 1068 1069 this.arguments = null; 1070 1071 this.children = null; 1072 this.implementationChildren = null; 1073 this.importedChildren = null; 1074 1075 this.delegates = null; 1076 this.implementationDelegates = null; 1077 this.importedDelegates = null; 1078 1079 this.variables = null; 1080 this.implementationVariables = null; 1081 } 1082 InternalCacheMetadata(bool createEmptyBindings, ref IList<ValidationError> validationErrors)1083 internal void InternalCacheMetadata(bool createEmptyBindings, ref IList<ValidationError> validationErrors) 1084 { 1085 OnInternalCacheMetadata(createEmptyBindings); 1086 1087 if (this.tempAutoGeneratedArguments != null) 1088 { 1089 Fx.Assert(this.tempAutoGeneratedArguments.Count > 0, "We should only have a non-null value here if we generated an argument"); 1090 if (!this.SkipArgumentResolution) 1091 { 1092 ActivityUtilities.Add(ref validationErrors, new ValidationError( 1093 SR.PublicReferencesOnActivityRequiringArgumentResolution(this.DisplayName), false, this)); 1094 } 1095 1096 if (this.arguments == null) 1097 { 1098 this.arguments = this.tempAutoGeneratedArguments; 1099 } 1100 else 1101 { 1102 for (int i = 0; i < this.tempAutoGeneratedArguments.Count; i++) 1103 { 1104 this.arguments.Add(this.tempAutoGeneratedArguments[i]); 1105 } 1106 } 1107 1108 this.tempAutoGeneratedArguments = null; 1109 } 1110 1111 if (this.arguments != null && this.arguments.Count > 1) 1112 { 1113 ActivityValidationServices.ValidateEvaluationOrder(this.arguments, this, ref this.tempValidationErrors); 1114 } 1115 1116 if (this.tempValidationErrors != null) 1117 { 1118 if (validationErrors == null) 1119 { 1120 validationErrors = new List<ValidationError>(); 1121 } 1122 1123 for (int i = 0; i < this.tempValidationErrors.Count; i++) 1124 { 1125 ValidationError validationError = this.tempValidationErrors[i]; 1126 1127 validationError.Source = this; 1128 validationError.Id = this.Id; 1129 1130 validationErrors.Add(validationError); 1131 } 1132 1133 this.tempValidationErrors = null; 1134 } 1135 1136 if (this.arguments == null) 1137 { 1138 this.arguments = emptyArguments; 1139 } 1140 else 1141 { 1142 this.symbolCount += this.arguments.Count; 1143 } 1144 1145 if (this.variables == null) 1146 { 1147 this.variables = emptyVariables; 1148 } 1149 else 1150 { 1151 this.symbolCount += this.variables.Count; 1152 } 1153 1154 if (this.implementationVariables == null) 1155 { 1156 this.implementationVariables = emptyVariables; 1157 } 1158 else 1159 { 1160 this.symbolCount += this.implementationVariables.Count; 1161 } 1162 1163 if (this.children == null) 1164 { 1165 this.children = emptyChildren; 1166 } 1167 1168 if (this.importedChildren == null) 1169 { 1170 this.importedChildren = emptyChildren; 1171 } 1172 1173 if (this.implementationChildren == null) 1174 { 1175 this.implementationChildren = emptyChildren; 1176 } 1177 1178 if (this.delegates == null) 1179 { 1180 this.delegates = emptyDelegates; 1181 } 1182 1183 if (this.importedDelegates == null) 1184 { 1185 this.importedDelegates = emptyDelegates; 1186 } 1187 1188 if (this.implementationDelegates == null) 1189 { 1190 this.implementationDelegates = emptyDelegates; 1191 } 1192 1193 this.isMetadataCached = CacheStates.Partial; 1194 } 1195 1196 // Note that this is relative to the type of walk we've done. If we 1197 // skipped implementation then we can still be "Cached" even though 1198 // we never ignored the implementation. SetCached(bool isSkippingPrivateChildren)1199 internal void SetCached(bool isSkippingPrivateChildren) 1200 { 1201 if (isSkippingPrivateChildren) 1202 { 1203 this.isMetadataCached = CacheStates.Partial; 1204 } 1205 else 1206 { 1207 this.isMetadataCached = CacheStates.Full; 1208 } 1209 } 1210 SetRuntimeReady()1211 internal void SetRuntimeReady() 1212 { 1213 this.isMetadataCached |= CacheStates.RuntimeReady; 1214 } 1215 OnInternalCacheMetadata(bool createEmptyBindings)1216 internal virtual void OnInternalCacheMetadata(bool createEmptyBindings) 1217 { 1218 // By running CacheMetadata first we allow the user 1219 // to set their Implementation during CacheMetadata. 1220 ActivityMetadata metadata = new ActivityMetadata(this, GetParentEnvironment(), createEmptyBindings); 1221 CacheMetadata(metadata); 1222 metadata.Dispose(); 1223 1224 if (this.Implementation != null) 1225 { 1226 this.runtimeImplementation = this.Implementation(); 1227 } 1228 else 1229 { 1230 this.runtimeImplementation = null; 1231 } 1232 1233 if (this.runtimeImplementation != null) 1234 { 1235 SetImplementationChildrenCollection(new Collection<Activity> 1236 { 1237 this.runtimeImplementation 1238 }); 1239 } 1240 } 1241 CacheMetadata(ActivityMetadata metadata)1242 protected virtual void CacheMetadata(ActivityMetadata metadata) 1243 { 1244 ReflectedInformation information = new ReflectedInformation(this); 1245 1246 SetImportedChildrenCollection(information.GetChildren()); 1247 SetVariablesCollection(information.GetVariables()); 1248 SetImportedDelegatesCollection(information.GetDelegates()); 1249 SetArgumentsCollection(information.GetArguments(), metadata.CreateEmptyBindings); 1250 } 1251 OnInternalCreateDynamicUpdateMap(DynamicUpdateMapBuilder.Finalizer finalizer, DynamicUpdateMapBuilder.IDefinitionMatcher matcher, Activity originalActivity)1252 internal virtual void OnInternalCreateDynamicUpdateMap(DynamicUpdateMapBuilder.Finalizer finalizer, 1253 DynamicUpdateMapBuilder.IDefinitionMatcher matcher, Activity originalActivity) 1254 { 1255 UpdateMapMetadata metadata = new UpdateMapMetadata(finalizer, matcher, this); 1256 try 1257 { 1258 OnCreateDynamicUpdateMap(metadata, originalActivity); 1259 } 1260 finally 1261 { 1262 metadata.Dispose(); 1263 } 1264 } 1265 OnCreateDynamicUpdateMap(UpdateMapMetadata metadata, Activity originalActivity)1266 protected virtual void OnCreateDynamicUpdateMap(UpdateMapMetadata metadata, Activity originalActivity) 1267 { 1268 } 1269 1270 internal void AddDefaultExtensionProvider<T>(Func<T> extensionProvider) 1271 where T : class 1272 { 1273 Fx.Assert(extensionProvider != null, "caller must verify"); 1274 Fx.Assert(this.rootActivity != null && this.rootActivity.rootProperties != null, "need a valid root"); this.rootActivity.rootProperties.AddDefaultExtensionProvider(extensionProvider)1275 this.rootActivity.rootProperties.AddDefaultExtensionProvider(extensionProvider); 1276 } 1277 RequireExtension(Type extensionType)1278 internal void RequireExtension(Type extensionType) 1279 { 1280 Fx.Assert(extensionType != null && !extensionType.IsValueType, "caller should verify we have a valid reference type"); 1281 Fx.Assert(this.rootActivity != null && this.rootActivity.rootProperties != null, "need a valid root"); 1282 this.rootActivity.rootProperties.RequireExtension(extensionType); 1283 } 1284 1285 // information used by root activities 1286 class RootProperties 1287 { 1288 Dictionary<string, Activity> singletonActivityNames; 1289 Dictionary<Type, WorkflowInstanceExtensionProvider> activityExtensionProviders; 1290 HashSet<Type> requiredExtensionTypes; 1291 RootProperties()1292 public RootProperties() 1293 { 1294 } 1295 1296 public bool HasBeenAssociatedWithAnInstance 1297 { 1298 get; 1299 set; 1300 } 1301 1302 public LocationReferenceEnvironment HostEnvironment 1303 { 1304 get; 1305 set; 1306 } 1307 1308 public Dictionary<string, List<RuntimeArgument>> OverloadGroups 1309 { 1310 get; 1311 set; 1312 } 1313 1314 public List<RuntimeArgument> RequiredArgumentsNotInOverloadGroups 1315 { 1316 get; 1317 set; 1318 } 1319 1320 public ValidationHelper.OverloadGroupEquivalenceInfo EquivalenceInfo 1321 { 1322 get; 1323 set; 1324 } 1325 1326 public int DefaultExtensionsCount 1327 { 1328 get 1329 { 1330 if (this.activityExtensionProviders != null) 1331 { 1332 return this.activityExtensionProviders.Count; 1333 } 1334 else 1335 { 1336 return 0; 1337 } 1338 } 1339 } 1340 1341 public int RequiredExtensionTypesCount 1342 { 1343 get 1344 { 1345 if (this.requiredExtensionTypes != null) 1346 { 1347 return this.requiredExtensionTypes.Count; 1348 } 1349 else 1350 { 1351 return 0; 1352 } 1353 } 1354 } 1355 GetActivityExtensionInformation(out Dictionary<Type, WorkflowInstanceExtensionProvider> activityExtensionProviders, out HashSet<Type> requiredActivityExtensionTypes)1356 public bool GetActivityExtensionInformation(out Dictionary<Type, WorkflowInstanceExtensionProvider> activityExtensionProviders, out HashSet<Type> requiredActivityExtensionTypes) 1357 { 1358 activityExtensionProviders = this.activityExtensionProviders; 1359 requiredActivityExtensionTypes = this.requiredExtensionTypes; 1360 return activityExtensionProviders != null || (requiredExtensionTypes != null && requiredExtensionTypes.Count > 0); 1361 } 1362 1363 public void AddDefaultExtensionProvider<T>(Func<T> extensionProvider) 1364 where T : class 1365 { 1366 Type key = typeof(T); 1367 if (this.activityExtensionProviders == null) 1368 { 1369 this.activityExtensionProviders = new Dictionary<Type, WorkflowInstanceExtensionProvider>(); 1370 } 1371 else 1372 { 1373 if (this.activityExtensionProviders.ContainsKey(key)) 1374 { 1375 return; // already have a provider of this type 1376 } 1377 } 1378 this.activityExtensionProviders.Add(key, new WorkflowInstanceExtensionProvider<T>(extensionProvider))1379 this.activityExtensionProviders.Add(key, new WorkflowInstanceExtensionProvider<T>(extensionProvider)); 1380 1381 // if we're providing an extension that exactly matches a required type, simplify further bookkeeping 1382 if (this.requiredExtensionTypes != null) 1383 { 1384 this.requiredExtensionTypes.Remove(key); 1385 } 1386 } 1387 RequireExtension(Type extensionType)1388 public void RequireExtension(Type extensionType) 1389 { 1390 // if we're providing an extension that exactly matches a required type, don't bother with further bookkeeping 1391 if (this.activityExtensionProviders != null && this.activityExtensionProviders.ContainsKey(extensionType)) 1392 { 1393 return; 1394 } 1395 1396 if (this.requiredExtensionTypes == null) 1397 { 1398 this.requiredExtensionTypes = new HashSet<Type>(); 1399 } 1400 this.requiredExtensionTypes.Add(extensionType); 1401 } 1402 IsSingletonActivityDeclared(string name)1403 public bool IsSingletonActivityDeclared(string name) 1404 { 1405 if (this.singletonActivityNames == null) 1406 { 1407 return false; 1408 } 1409 else 1410 { 1411 return this.singletonActivityNames.ContainsKey(name); 1412 } 1413 } 1414 DeclareSingletonActivity(string name, Activity activity)1415 public void DeclareSingletonActivity(string name, Activity activity) 1416 { 1417 if (this.singletonActivityNames == null) 1418 { 1419 this.singletonActivityNames = new Dictionary<string, Activity>(1); 1420 } 1421 1422 this.singletonActivityNames.Add(name, activity); 1423 } 1424 GetSingletonActivity(string name)1425 public Activity GetSingletonActivity(string name) 1426 { 1427 Activity result = null; 1428 if (this.singletonActivityNames != null) 1429 { 1430 this.singletonActivityNames.TryGetValue(name, out result); 1431 } 1432 1433 return result; 1434 } 1435 } 1436 1437 internal class ReflectedInformation 1438 { 1439 Activity parent; 1440 1441 Collection<RuntimeArgument> arguments; 1442 Collection<Variable> variables; 1443 Collection<Activity> children; 1444 Collection<ActivityDelegate> delegates; 1445 1446 static Type DictionaryArgumentHelperType = typeof(DictionaryArgumentHelper<>); 1447 static Type OverloadGroupAttributeType = typeof(OverloadGroupAttribute); 1448 ReflectedInformation(Activity owner)1449 public ReflectedInformation(Activity owner) 1450 : this(owner, ReflectedType.All) 1451 { 1452 } 1453 ReflectedInformation(Activity activity, ReflectedType reflectType)1454 ReflectedInformation(Activity activity, ReflectedType reflectType) 1455 { 1456 this.parent = activity; 1457 1458 // reflect over our activity and gather relevant pieces of the system so that the developer 1459 // doesn't need to worry about "zipping up" his model to the constructs necessary for the 1460 // runtime to function correctly 1461 foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(activity)) 1462 { 1463 ArgumentDirection direction; 1464 Type argumentType; 1465 if ((reflectType & ReflectedType.Argument) == ReflectedType.Argument && 1466 ActivityUtilities.TryGetArgumentDirectionAndType(propertyDescriptor.PropertyType, out direction, out argumentType)) 1467 { 1468 // We only do our magic for generic argument types. If the property is a non-generic 1469 // argument type then that means the type of the RuntimeArgument should be based on 1470 // the type of the argument bound to it. The activity author is responsible for dealing 1471 // with these dynamic typing cases. 1472 if (propertyDescriptor.PropertyType.IsGenericType) 1473 { 1474 bool isRequired = GetIsArgumentRequired(propertyDescriptor); 1475 List<string> overloadGroupNames = GetOverloadGroupNames(propertyDescriptor); 1476 RuntimeArgument argument = new RuntimeArgument(propertyDescriptor.Name, argumentType, direction, isRequired, overloadGroupNames, propertyDescriptor, activity); 1477 Add<RuntimeArgument>(ref this.arguments, argument); 1478 } 1479 } 1480 else if ((reflectType & ReflectedType.Variable) == ReflectedType.Variable && 1481 ActivityUtilities.IsVariableType(propertyDescriptor.PropertyType)) 1482 { 1483 Variable variable = propertyDescriptor.GetValue(activity) as Variable; 1484 if (variable != null) 1485 { 1486 Add<Variable>(ref this.variables, variable); 1487 } 1488 } 1489 else if ((reflectType & ReflectedType.Child) == ReflectedType.Child && 1490 ActivityUtilities.IsActivityType(propertyDescriptor.PropertyType)) 1491 { 1492 Activity workflowElement = propertyDescriptor.GetValue(activity) as Activity; 1493 Add<Activity>(ref this.children, workflowElement); 1494 } 1495 else if ((reflectType & ReflectedType.ActivityDelegate) == ReflectedType.ActivityDelegate && 1496 ActivityUtilities.IsActivityDelegateType(propertyDescriptor.PropertyType)) 1497 { 1498 ActivityDelegate activityDelegate = propertyDescriptor.GetValue(activity) as ActivityDelegate; 1499 Add<ActivityDelegate>(ref this.delegates, activityDelegate); 1500 } 1501 else 1502 { 1503 Type innerType; 1504 bool foundMatch = false; 1505 if ((reflectType & ReflectedType.Argument) == ReflectedType.Argument) 1506 { 1507 object property = propertyDescriptor.GetValue(activity); 1508 if (property != null) 1509 { 1510 IList<RuntimeArgument> runtimeArguments = DictionaryArgumentHelper.TryGetRuntimeArguments(property, propertyDescriptor.Name); 1511 if (runtimeArguments != null) 1512 { 1513 this.AddCollection(ref this.arguments, runtimeArguments); 1514 foundMatch = true; 1515 } 1516 else if (ActivityUtilities.IsArgumentDictionaryType(propertyDescriptor.PropertyType, out innerType)) 1517 { 1518 Type concreteHelperType = DictionaryArgumentHelperType.MakeGenericType(innerType); 1519 DictionaryArgumentHelper helper = Activator.CreateInstance(concreteHelperType, new object[] { property, propertyDescriptor.Name }) as DictionaryArgumentHelper; 1520 this.AddCollection(ref this.arguments, helper.RuntimeArguments); 1521 foundMatch = true; 1522 } 1523 } 1524 } 1525 1526 if (!foundMatch && ActivityUtilities.IsKnownCollectionType(propertyDescriptor.PropertyType, out innerType)) 1527 { 1528 if ((reflectType & ReflectedType.Variable) == ReflectedType.Variable && 1529 ActivityUtilities.IsVariableType(innerType)) 1530 { 1531 IEnumerable enumerable = propertyDescriptor.GetValue(activity) as IEnumerable; 1532 1533 AddCollection(ref this.variables, enumerable); 1534 } 1535 else if ((reflectType & ReflectedType.Child) == ReflectedType.Child && 1536 ActivityUtilities.IsActivityType(innerType, false)) 1537 { 1538 IEnumerable enumerable = propertyDescriptor.GetValue(activity) as IEnumerable; 1539 1540 AddCollection(ref this.children, enumerable); 1541 } 1542 else if ((reflectType & ReflectedType.ActivityDelegate) == ReflectedType.ActivityDelegate && 1543 ActivityUtilities.IsActivityDelegateType(innerType)) 1544 { 1545 IEnumerable enumerable = propertyDescriptor.GetValue(activity) as IEnumerable; 1546 1547 AddCollection(ref this.delegates, enumerable); 1548 } 1549 } 1550 } 1551 } 1552 } 1553 GetArguments(Activity parent)1554 public static Collection<RuntimeArgument> GetArguments(Activity parent) 1555 { 1556 Collection<RuntimeArgument> arguments = null; 1557 1558 if (parent != null) 1559 { 1560 arguments = new ReflectedInformation(parent, ReflectedType.Argument).GetArguments(); 1561 } 1562 1563 if (arguments == null) 1564 { 1565 arguments = new Collection<RuntimeArgument>(); 1566 } 1567 1568 return arguments; 1569 } 1570 GetVariables(Activity parent)1571 public static Collection<Variable> GetVariables(Activity parent) 1572 { 1573 Collection<Variable> variables = null; 1574 1575 if (parent != null) 1576 { 1577 variables = new ReflectedInformation(parent, ReflectedType.Variable).GetVariables(); 1578 } 1579 1580 if (variables == null) 1581 { 1582 variables = new Collection<Variable>(); 1583 } 1584 1585 return variables; 1586 } 1587 GetChildren(Activity parent)1588 public static Collection<Activity> GetChildren(Activity parent) 1589 { 1590 Collection<Activity> children = null; 1591 1592 if (parent != null) 1593 { 1594 children = new ReflectedInformation(parent, ReflectedType.Child).GetChildren(); 1595 } 1596 1597 if (children == null) 1598 { 1599 children = new Collection<Activity>(); 1600 } 1601 1602 return children; 1603 } 1604 GetDelegates(Activity parent)1605 public static Collection<ActivityDelegate> GetDelegates(Activity parent) 1606 { 1607 Collection<ActivityDelegate> delegates = null; 1608 1609 if (parent != null) 1610 { 1611 delegates = new ReflectedInformation(parent, ReflectedType.ActivityDelegate).GetDelegates(); 1612 } 1613 1614 if (delegates == null) 1615 { 1616 delegates = new Collection<ActivityDelegate>(); 1617 } 1618 1619 return delegates; 1620 } 1621 GetArguments()1622 public Collection<RuntimeArgument> GetArguments() 1623 { 1624 return this.arguments; 1625 } 1626 GetVariables()1627 public Collection<Variable> GetVariables() 1628 { 1629 return this.variables; 1630 } 1631 GetChildren()1632 public Collection<Activity> GetChildren() 1633 { 1634 return this.children; 1635 } 1636 GetDelegates()1637 public Collection<ActivityDelegate> GetDelegates() 1638 { 1639 return this.delegates; 1640 } 1641 1642 void AddCollection<T>(ref Collection<T> list, IEnumerable enumerable) 1643 where T : class 1644 { 1645 if (enumerable != null) 1646 { 1647 foreach (object obj in enumerable) 1648 { 1649 if (obj != null && obj is T) 1650 { 1651 Add<T>(ref list, (T)obj); 1652 } 1653 } 1654 } 1655 } 1656 Add(ref Collection<T> list, T data)1657 void Add<T>(ref Collection<T> list, T data) 1658 { 1659 if (data != null) 1660 { 1661 if (list == null) 1662 { 1663 list = new Collection<T>(); 1664 } 1665 list.Add(data); 1666 } 1667 } 1668 GetIsArgumentRequired(PropertyDescriptor propertyDescriptor)1669 bool GetIsArgumentRequired(PropertyDescriptor propertyDescriptor) 1670 { 1671 return propertyDescriptor.Attributes[typeof(RequiredArgumentAttribute)] != null; 1672 } 1673 GetOverloadGroupNames(PropertyDescriptor propertyDescriptor)1674 List<string> GetOverloadGroupNames(PropertyDescriptor propertyDescriptor) 1675 { 1676 List<string> overloadGroupNames = new List<string>(0); 1677 AttributeCollection propertyAttributes = propertyDescriptor.Attributes; 1678 for (int i = 0; i < propertyAttributes.Count; i++) 1679 { 1680 Attribute attribute = propertyAttributes[i]; 1681 if (ReflectedInformation.OverloadGroupAttributeType.IsAssignableFrom(attribute.GetType())) 1682 { 1683 overloadGroupNames.Add(((OverloadGroupAttribute)attribute).GroupName); 1684 } 1685 } 1686 return overloadGroupNames; 1687 } 1688 1689 [Flags] 1690 enum ReflectedType 1691 { 1692 Argument = 0X1, 1693 Variable = 0X2, 1694 Child = 0X4, 1695 ActivityDelegate = 0X8, 1696 All = 0XF 1697 } 1698 1699 class DictionaryArgumentHelper 1700 { DictionaryArgumentHelper()1701 protected DictionaryArgumentHelper() 1702 { 1703 } 1704 1705 public IList<RuntimeArgument> RuntimeArguments 1706 { 1707 get; 1708 protected set; 1709 } 1710 TryGetRuntimeArguments(object propertyValue, string propertyName)1711 public static IList<RuntimeArgument> TryGetRuntimeArguments(object propertyValue, string propertyName) 1712 { 1713 // special case each of the non-generic argument types to avoid reflection costs 1714 1715 IEnumerable<KeyValuePair<string, Argument>> argumentEnumerable = propertyValue as IEnumerable<KeyValuePair<string, Argument>>; 1716 if (argumentEnumerable != null) 1717 { 1718 return GetRuntimeArguments(argumentEnumerable, propertyName); 1719 } 1720 1721 IEnumerable<KeyValuePair<string, InArgument>> inArgumentEnumerable = propertyValue as IEnumerable<KeyValuePair<string, InArgument>>; 1722 if (inArgumentEnumerable != null) 1723 { 1724 return GetRuntimeArguments(inArgumentEnumerable, propertyName); 1725 } 1726 1727 IEnumerable<KeyValuePair<string, OutArgument>> outArgumentEnumerable = propertyValue as IEnumerable<KeyValuePair<string, OutArgument>>; 1728 if (outArgumentEnumerable != null) 1729 { 1730 return GetRuntimeArguments(outArgumentEnumerable, propertyName); 1731 } 1732 1733 IEnumerable<KeyValuePair<string, InOutArgument>> inOutArgumentEnumerable = propertyValue as IEnumerable<KeyValuePair<string, InOutArgument>>; 1734 if (inOutArgumentEnumerable != null) 1735 { 1736 return GetRuntimeArguments(inOutArgumentEnumerable, propertyName); 1737 } 1738 1739 return null; 1740 } 1741 1742 protected static IList<RuntimeArgument> GetRuntimeArguments<T>(IEnumerable<KeyValuePair<string, T>> argumentDictionary, string propertyName) where T : Argument 1743 { 1744 IList<RuntimeArgument> runtimeArguments = new List<RuntimeArgument>(); 1745 1746 foreach (KeyValuePair<string, T> pair in argumentDictionary) 1747 { 1748 string key = pair.Key; 1749 Argument value = pair.Value; 1750 1751 if (value == null) 1752 { 1753 string argName = (key == null) ? "<null>" : key; 1754 throw FxTrace.Exception.AsError(new ValidationException(SR.MissingArgument(argName, propertyName))); 1755 } 1756 if (string.IsNullOrEmpty(key)) 1757 { 1758 throw FxTrace.Exception.AsError(new ValidationException(SR.MissingNameProperty(value.ArgumentType))); 1759 } 1760 1761 RuntimeArgument runtimeArgument = new RuntimeArgument(key, value.ArgumentType, value.Direction, false, null, value); 1762 runtimeArguments.Add(runtimeArgument); 1763 } 1764 1765 return runtimeArguments; 1766 } 1767 } 1768 1769 class DictionaryArgumentHelper<T> : DictionaryArgumentHelper where T : Argument 1770 { DictionaryArgumentHelper(object propertyValue, string propertyName)1771 public DictionaryArgumentHelper(object propertyValue, string propertyName) 1772 : base() 1773 { 1774 IEnumerable<KeyValuePair<string, T>> argumentDictionary = propertyValue as IEnumerable<KeyValuePair<string, T>>; 1775 1776 this.RuntimeArguments = GetRuntimeArguments(argumentDictionary, propertyName); 1777 } 1778 } 1779 1780 } 1781 1782 internal enum RelationshipType : byte 1783 { 1784 Child = 0x00, 1785 ImportedChild = 0x01, 1786 ImplementationChild = 0x02, 1787 DelegateHandler = 0x03, 1788 ArgumentExpression = 0x04, 1789 VariableDefault = 0x05 1790 } 1791 1792 enum CacheStates : byte 1793 { 1794 // We don't have valid cached data 1795 Uncached = 0x00, 1796 1797 // The next two states are mutually exclusive: 1798 1799 // The activity has its own metadata cached, or private implementation are skipped 1800 Partial = 0x01, 1801 1802 // The activity has its own metadata and its private implementation cached 1803 // We can make use of the roll-up metadata (like 1804 // SubtreeHasConstraints). 1805 Full = 0x02, 1806 1807 // The next state can be ORed with the last two: 1808 1809 // The cached data is ready for runtime use 1810 RuntimeReady = 0x04 1811 } 1812 } 1813 1814 [TypeConverter(typeof(ActivityWithResultConverter))] 1815 [ValueSerializer(typeof(ActivityWithResultValueSerializer))] 1816 public abstract class Activity<TResult> : ActivityWithResult 1817 { 1818 // alternatives are extended through DynamicActivity<TResult>, CodeActivity<TResult>, and NativeActivity<TResult> Activity()1819 protected Activity() 1820 : base() 1821 { 1822 } 1823 1824 [DefaultValue(null)] 1825 public new OutArgument<TResult> Result 1826 { 1827 get; 1828 set; 1829 } 1830 1831 internal override Type InternalResultType 1832 { 1833 get 1834 { 1835 return typeof(TResult); 1836 } 1837 } 1838 1839 internal override OutArgument ResultCore 1840 { 1841 get 1842 { 1843 return this.Result; 1844 } 1845 set 1846 { 1847 this.Result = value as OutArgument<TResult>; 1848 1849 if (this.Result == null && value != null) 1850 { 1851 throw FxTrace.Exception.Argument("value", SR.ResultArgumentMustBeSpecificType(typeof(TResult))); 1852 } 1853 } 1854 } 1855 operator Activity<TResult>(TResult constValue)1856 public static implicit operator Activity<TResult>(TResult constValue) 1857 { 1858 return FromValue(constValue); 1859 } 1860 operator Activity<TResult>(Variable variable)1861 public static implicit operator Activity<TResult>(Variable variable) 1862 { 1863 return FromVariable(variable); 1864 } 1865 operator Activity<TResult>(Variable<TResult> variable)1866 public static implicit operator Activity<TResult>(Variable<TResult> variable) 1867 { 1868 return FromVariable(variable); 1869 } 1870 FromValue(TResult constValue)1871 public static Activity<TResult> FromValue(TResult constValue) 1872 { 1873 return new Literal<TResult> { Value = constValue }; 1874 } 1875 FromVariable(Variable variable)1876 public static Activity<TResult> FromVariable(Variable variable) 1877 { 1878 if (variable == null) 1879 { 1880 throw FxTrace.Exception.ArgumentNull("variable"); 1881 } 1882 1883 if (TypeHelper.AreTypesCompatible(variable.Type, typeof(TResult))) 1884 { 1885 return new VariableValue<TResult> { Variable = variable }; 1886 } 1887 else 1888 { 1889 Type locationGenericType; 1890 if (ActivityUtilities.IsLocationGenericType(typeof(TResult), out locationGenericType)) 1891 { 1892 if (locationGenericType == variable.Type) 1893 { 1894 return (Activity<TResult>)ActivityUtilities.CreateVariableReference(variable); 1895 } 1896 } 1897 } 1898 1899 throw FxTrace.Exception.Argument("variable", SR.ConvertVariableToValueExpressionFailed(variable.GetType().FullName, typeof(Activity<TResult>).FullName)); 1900 } 1901 1902 [SuppressMessage(FxCop.Category.Design, FxCop.Rule.ConsiderPassingBaseTypesAsParameters, 1903 Justification = "Generic needed for type inference")] FromVariable(Variable<TResult> variable)1904 public static Activity<TResult> FromVariable(Variable<TResult> variable) 1905 { 1906 if (variable == null) 1907 { 1908 throw FxTrace.Exception.ArgumentNull("variable"); 1909 } 1910 1911 return new VariableValue<TResult>(variable); 1912 } 1913 IsResultArgument(RuntimeArgument argument)1914 internal override bool IsResultArgument(RuntimeArgument argument) 1915 { 1916 return object.ReferenceEquals(argument, this.ResultRuntimeArgument); 1917 } 1918 OnInternalCacheMetadata(bool createEmptyBindings)1919 internal sealed override void OnInternalCacheMetadata(bool createEmptyBindings) 1920 { 1921 OnInternalCacheMetadataExceptResult(createEmptyBindings); 1922 1923 bool foundResult = false; 1924 1925 // This could be null at this point 1926 IList<RuntimeArgument> runtimeArguments = this.RuntimeArguments; 1927 1928 int runtimeArgumentCount = 0; 1929 1930 if (runtimeArguments != null) 1931 { 1932 runtimeArgumentCount = runtimeArguments.Count; 1933 1934 for (int i = 0; i < runtimeArgumentCount; i++) 1935 { 1936 RuntimeArgument argument = runtimeArguments[i]; 1937 1938 if (argument.Name == "Result") 1939 { 1940 foundResult = true; 1941 1942 if (argument.Type != typeof(TResult) || argument.Direction != ArgumentDirection.Out) 1943 { 1944 // The user supplied "Result" is incorrect so we 1945 // log a violation. 1946 AddTempValidationError(new ValidationError(SR.ResultArgumentHasRequiredTypeAndDirection(typeof(TResult), argument.Direction, argument.Type))); 1947 } 1948 else if (!IsBoundArgumentCorrect(argument, createEmptyBindings)) 1949 { 1950 // The user supplied "Result" is not bound to the correct 1951 // argument object. 1952 AddTempValidationError(new ValidationError(SR.ResultArgumentMustBeBoundToResultProperty)); 1953 } 1954 else 1955 { 1956 // The user supplied "Result" is correct so we 1957 // cache it. 1958 this.ResultRuntimeArgument = argument; 1959 } 1960 1961 break; 1962 } 1963 } 1964 } 1965 1966 if (!foundResult) 1967 { 1968 this.ResultRuntimeArgument = new RuntimeArgument("Result", typeof(TResult), ArgumentDirection.Out); 1969 1970 if (this.Result == null) 1971 { 1972 if (createEmptyBindings) 1973 { 1974 this.Result = new OutArgument<TResult>(); 1975 Argument.Bind(this.Result, this.ResultRuntimeArgument); 1976 } 1977 else 1978 { 1979 OutArgument<TResult> tempArgument = new OutArgument<TResult>(); 1980 Argument.Bind(tempArgument, this.ResultRuntimeArgument); 1981 } 1982 } 1983 else 1984 { 1985 Argument.Bind(this.Result, this.ResultRuntimeArgument); 1986 } 1987 1988 1989 AddArgument(this.ResultRuntimeArgument, createEmptyBindings); 1990 } 1991 } 1992 IsBoundArgumentCorrect(RuntimeArgument argument, bool createEmptyBindings)1993 bool IsBoundArgumentCorrect(RuntimeArgument argument, bool createEmptyBindings) 1994 { 1995 if (createEmptyBindings) 1996 { 1997 // We must match if we've gone through 1998 // RuntimeArgument.SetupBinding with 1999 // createEmptyBindings == true. 2000 return object.ReferenceEquals(argument.BoundArgument, this.Result); 2001 } 2002 else 2003 { 2004 // Otherwise, if the Result is null then 2005 // SetupBinding has created a default 2006 // BoundArgument which is fine. If it 2007 // is non-null then it had better match. 2008 return this.Result == null || object.ReferenceEquals(argument.BoundArgument, this.Result); 2009 } 2010 } 2011 OnInternalCacheMetadataExceptResult(bool createEmptyBindings)2012 internal virtual void OnInternalCacheMetadataExceptResult(bool createEmptyBindings) 2013 { 2014 // default to Activity's behavior 2015 base.OnInternalCacheMetadata(createEmptyBindings); 2016 } 2017 InternalExecuteInResolutionContextUntyped(CodeActivityContext resolutionContext)2018 internal override object InternalExecuteInResolutionContextUntyped(CodeActivityContext resolutionContext) 2019 { 2020 return InternalExecuteInResolutionContext(resolutionContext); 2021 } 2022 InternalExecuteInResolutionContext(CodeActivityContext resolutionContext)2023 internal virtual TResult InternalExecuteInResolutionContext(CodeActivityContext resolutionContext) 2024 { 2025 throw Fx.AssertAndThrow("This should only be called on CodeActivity<T>"); 2026 } 2027 } 2028 } 2029 2030 2031