1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //-----------------------------------------------------------------------------
5 namespace System.Activities.Statements
7 using System.Collections.Generic;
8 using System.Collections.ObjectModel;
9 using System.Globalization;
11 using System.Reflection;
13 using System.Activities.Expressions;
14 using System.Threading;
16 // Helper class for InvokeMethod.
17 // Factory for MethodExecutor strategies. Conceptually, resolves to the correct MethodInfo based on target type,
18 // method name, parameters, and async flags + availability of Begin/End paired methods of the correct static-ness.
19 sealed class MethodResolver
22 static readonly BindingFlags staticBindingFlags = BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static;
23 static readonly BindingFlags instanceBindingFlags = BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance;
24 static readonly string staticString = "static"; // Used in error messages below. Technical term, not localizable.
25 static readonly string instanceString = "instance"; // Used in error messages below. Technical term, not localizable.
26 MethodInfo syncMethod;
27 MethodInfo beginMethod;
30 public MethodResolver()
34 public Collection<Type> GenericTypeArguments { get; set; }
36 public string MethodName { get; set; }
38 public Collection<Argument> Parameters { get; set; }
40 public RuntimeArgument Result { get; set; }
42 public InArgument TargetObject { get; set; }
44 public Type TargetType { get; set; }
46 public bool RunAsynchronously { get; set; }
48 public Activity Parent { get; set; }
50 // Sometimes we may know the result type even if it won't be used,
51 // i.e. it comes from an InvokeMethod<T>. We will want to generate
52 // errors if it doesn't match the method's return value.
53 internal Type ResultType { get; set; }
55 static bool HaveParameterArray(ParameterInfo[] parameters)
57 if (parameters.Length > 0)
59 ParameterInfo last = parameters[parameters.Length - 1];
60 return last.GetCustomAttributes(typeof(ParamArrayAttribute), true).Length > 0;
68 // The Arguments added by the activity are named according to the method resolved by the MethodResolver.
69 public void RegisterParameters(IList<RuntimeArgument> arguments)
71 bool useAsyncPattern = this.RunAsynchronously && this.beginMethod != null && this.endMethod != null;
73 if (this.syncMethod != null || useAsyncPattern)
75 ParameterInfo[] formalParameters;
77 string paramArrayBaseName = "";
78 bool haveParameterArray = false;
82 formalParameters = this.beginMethod.GetParameters();
83 formalParamCount = formalParameters.Length - 2;
87 formalParameters = this.syncMethod.GetParameters();
88 haveParameterArray = HaveParameterArray(formalParameters);
90 if (haveParameterArray)
92 formalParamCount = formalParameters.Length - 1;
93 paramArrayBaseName = formalParameters[formalParamCount].Name;
97 formalParamCount = formalParameters.Length;
101 for (int i = 0; i < formalParamCount; i++)
103 string name = formalParameters[i].Name;
104 //for some methods like int[,].Get(int,int), formal parameters have no names in reflection info
105 if (string.IsNullOrEmpty(name))
107 name = "Parameter" + i;
110 RuntimeArgument argument = new RuntimeArgument(name, Parameters[i].ArgumentType, Parameters[i].Direction, true);
111 Argument.Bind(Parameters[i], argument);
112 arguments.Add(argument);
114 if (!useAsyncPattern && haveParameterArray)
116 // Attempt to uniquify parameter names
117 if (name.StartsWith(paramArrayBaseName, false, null))
120 if (int.TryParse(name.Substring(paramArrayBaseName.Length), NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out n))
122 paramArrayBaseName += "_";
128 if (!useAsyncPattern && haveParameterArray)
130 // RuntimeArgument bindings need names. In the case of params arrays, synthesize names based on the name of the formal params parameter
132 int paramArrayCount = Parameters.Count - formalParamCount;
134 for (int i = 0; i < paramArrayCount; i++)
136 string name = paramArrayBaseName + i;
137 int index = formalParamCount + i;
138 RuntimeArgument argument = new RuntimeArgument(name, Parameters[index].ArgumentType, Parameters[index].Direction, true);
139 Argument.Bind(Parameters[index], argument);
140 arguments.Add(argument);
146 // We're still at design-time: make up "fake" arguments based on the parameters
147 for (int i = 0; i < Parameters.Count; i++)
149 string name = "argument" + i;
150 RuntimeArgument argument = new RuntimeArgument(name, Parameters[i].ArgumentType, Parameters[i].Direction, true);
151 Argument.Bind(Parameters[i], argument);
152 arguments.Add(argument);
159 bool useAsyncPattern = this.RunAsynchronously && this.beginMethod != null && this.endMethod != null;
163 if (TD.InvokeMethodUseAsyncPatternIsEnabled())
165 TD.InvokeMethodUseAsyncPattern(this.Parent.DisplayName, this.beginMethod.ToString(), this.endMethod.ToString());
170 if (this.RunAsynchronously)
172 if (TD.InvokeMethodDoesNotUseAsyncPatternIsEnabled())
174 TD.InvokeMethodDoesNotUseAsyncPattern(this.Parent.DisplayName);
180 // Set methodExecutor, returning an error string if there are any problems (ambiguous match, etc.).
181 public void DetermineMethodInfo(CodeActivityMetadata metadata, MruCache<MethodInfo, Func<object, object[], object>> funcCache, ReaderWriterLockSlim locker,
182 ref MethodExecutor methodExecutor)
184 bool returnEarly = false;
186 MethodExecutor oldMethodExecutor = methodExecutor;
187 methodExecutor = null;
188 if (string.IsNullOrEmpty(this.MethodName))
190 metadata.AddValidationError(SR.ActivityPropertyMustBeSet("MethodName", this.Parent.DisplayName));
194 Type targetType = this.TargetType;
196 // If TargetType and the type of TargetObject are both set, it's an error.
197 if (targetType != null && this.TargetObject != null && !this.TargetObject.IsEmpty)
199 metadata.AddValidationError(SR.TargetTypeAndTargetObjectAreMutuallyExclusive(this.Parent.GetType().Name, this.Parent.DisplayName));
203 // If TargetType was set, look for a static method. If TargetObject was set, look for an instance method. They can't both be set.
204 BindingFlags bindingFlags = this.TargetType != null ? staticBindingFlags : instanceBindingFlags;
205 string bindingType = bindingFlags == staticBindingFlags ? staticString : instanceString;
207 if (targetType == null)
209 if (this.TargetObject != null && !this.TargetObject.IsEmpty)
211 targetType = this.TargetObject.ArgumentType;
215 metadata.AddValidationError(SR.OneOfTwoPropertiesMustBeSet("TargetObject", "TargetType", this.Parent.GetType().Name, this.Parent.DisplayName));
220 // We've had one or more constraint violations already
226 // Convert OutArgs and InOutArgs to out/ref types before resolution
227 Type[] parameterTypes =
228 Parameters.Select(argument => argument.Direction == ArgumentDirection.In ? argument.ArgumentType : argument.ArgumentType.MakeByRefType())
231 Type[] genericTypeArguments = this.GenericTypeArguments.ToArray();
233 InheritanceAndParamArrayAwareBinder methodBinder = new InheritanceAndParamArrayAwareBinder(targetType, genericTypeArguments, this.Parent);
235 // It may be possible to know (and check) the resultType even if the result won't be assigned anywhere.
236 // Used 1.) for detecting async pattern, and 2.) to make sure we selected the correct MethodInfo.
237 Type resultType = this.ResultType;
239 if (this.RunAsynchronously)
241 int formalParamCount = parameterTypes.Length;
242 Type[] beginMethodParameterTypes = new Type[formalParamCount + 2];
243 for (int i = 0; i < formalParamCount; i++)
245 beginMethodParameterTypes[i] = parameterTypes[i];
247 beginMethodParameterTypes[formalParamCount] = typeof(AsyncCallback);
248 beginMethodParameterTypes[formalParamCount + 1] = typeof(object);
250 Type[] endMethodParameterTypes = { typeof(IAsyncResult) };
252 this.beginMethod = Resolve(targetType, "Begin" + this.MethodName, bindingFlags,
253 methodBinder, beginMethodParameterTypes, genericTypeArguments, true);
254 if (this.beginMethod != null && !this.beginMethod.ReturnType.Equals(typeof(IAsyncResult)))
256 this.beginMethod = null;
258 this.endMethod = Resolve(targetType, "End" + this.MethodName, bindingFlags,
259 methodBinder, endMethodParameterTypes, genericTypeArguments, true);
260 if (this.endMethod != null && resultType != null && !TypeHelper.AreTypesCompatible(this.endMethod.ReturnType, resultType))
262 metadata.AddValidationError(SR.ReturnTypeIncompatible(this.endMethod.ReturnType.Name, MethodName, targetType.Name, this.Parent.DisplayName, resultType.Name));
263 this.endMethod = null;
267 if (this.beginMethod != null && this.endMethod != null && this.beginMethod.IsStatic == this.endMethod.IsStatic)
269 if (!(oldMethodExecutor is AsyncPatternMethodExecutor) ||
270 !((AsyncPatternMethodExecutor)oldMethodExecutor).IsTheSame(this.beginMethod, this.endMethod))
272 methodExecutor = new AsyncPatternMethodExecutor(metadata, this.beginMethod, this.endMethod, this.Parent,
273 this.TargetType, this.TargetObject, this.Parameters, this.Result, funcCache, locker);
277 methodExecutor = new AsyncPatternMethodExecutor((AsyncPatternMethodExecutor)oldMethodExecutor,
278 this.TargetType, this.TargetObject, this.Parameters, this.Result);
287 result = Resolve(targetType, this.MethodName, bindingFlags,
288 methodBinder, parameterTypes, genericTypeArguments, false);
290 catch (AmbiguousMatchException)
292 metadata.AddValidationError(SR.DuplicateMethodFound(targetType.Name, bindingType, MethodName, this.Parent.DisplayName));
298 metadata.AddValidationError(SR.PublicMethodWithMatchingParameterDoesNotExist(targetType.Name, bindingType, MethodName, this.Parent.DisplayName));
301 else if (resultType != null && !TypeHelper.AreTypesCompatible(result.ReturnType, resultType))
303 metadata.AddValidationError(
304 SR.ReturnTypeIncompatible(result.ReturnType.Name, MethodName,
305 targetType.Name, this.Parent.DisplayName, resultType.Name));
310 this.syncMethod = result;
311 if (this.RunAsynchronously)
313 if (!(oldMethodExecutor is AsyncWaitCallbackMethodExecutor) ||
314 !((AsyncWaitCallbackMethodExecutor)oldMethodExecutor).IsTheSame(this.syncMethod))
316 methodExecutor = new AsyncWaitCallbackMethodExecutor(metadata, this.syncMethod, this.Parent,
317 this.TargetType, this.TargetObject, this.Parameters, this.Result, funcCache, locker);
321 methodExecutor = new AsyncWaitCallbackMethodExecutor((AsyncWaitCallbackMethodExecutor)oldMethodExecutor,
322 this.TargetType, this.TargetObject, this.Parameters, this.Result);
326 else if (!(oldMethodExecutor is SyncMethodExecutor) ||
327 !((SyncMethodExecutor)oldMethodExecutor).IsTheSame(this.syncMethod))
329 methodExecutor = new SyncMethodExecutor(metadata, this.syncMethod, this.Parent, this.TargetType,
330 this.TargetObject, this.Parameters, this.Result, funcCache, locker);
334 methodExecutor = new SyncMethodExecutor((SyncMethodExecutor)oldMethodExecutor, this.TargetType,
335 this.TargetObject, this.Parameters, this.Result);
341 // returns null MethodInfo on failure
342 MethodInfo Resolve(Type targetType, string methodName, BindingFlags bindingFlags,
343 InheritanceAndParamArrayAwareBinder methodBinder, Type[] parameterTypes, Type[] genericTypeArguments, bool suppressAmbiguityException)
348 methodBinder.SelectMethodCalled = false;
349 method = targetType.GetMethod(methodName, bindingFlags,
350 methodBinder, CallingConventions.Any, parameterTypes, null);
352 catch (AmbiguousMatchException)
354 if (suppressAmbiguityException) // For Begin/End methods, ambiguity just means no match
358 else // For a regular sync method, ambiguity is distinct from no match and gets an explicit error message
364 if (method != null && !methodBinder.SelectMethodCalled && genericTypeArguments.Length > 0)
365 // methodBinder is only used when there's more than one possible match, so method might still be generic
367 method = Instantiate(method, genericTypeArguments); // if it fails because of e.g. constraints it will just become null
372 // returns null on failure instead of throwing an exception (okay because it's an internal method)
373 static MethodInfo Instantiate(MethodInfo method, Type[] genericTypeArguments)
375 if (method.ContainsGenericParameters && method.GetGenericArguments().Length == genericTypeArguments.Length)
379 // Must be a MethodInfo because we've already filtered out constructors
380 return ((MethodInfo)method).MakeGenericMethod(genericTypeArguments);
382 catch (ArgumentException)
384 // Constraint violations will throw this exception--don't add to candidates
395 // Store information about a particular asynchronous method call so we can update out/ref parameters, know
396 // when/what to return, etc.
397 class InvokeMethodInstanceData
399 public object TargetObject { get; set; }
400 public object[] ActualParameters { get; set; }
401 public object ReturnValue { get; set; }
402 public bool ExceptionWasThrown { get; set; }
403 public Exception Exception { get; set; }
406 class InheritanceAndParamArrayAwareBinder : Binder
408 Type[] genericTypeArguments;
410 Type declaringType; // Methods declared directly on this type are preferred, followed by methods on its parents, etc.
412 internal bool SelectMethodCalled; // If this binder is actually used in resolution, it gets to do things like instantiate methods.
413 // Set this flag to false before calling Type.GetMethod. Check this flag after.
415 Activity parentActivity; // Used for generating AmbiguousMatchException error message
417 public InheritanceAndParamArrayAwareBinder(Type declaringType, Type[] genericTypeArguments, Activity parentActivity)
419 this.declaringType = declaringType;
420 this.genericTypeArguments = genericTypeArguments;
421 this.parentActivity = parentActivity;
424 public override FieldInfo BindToField(BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture)
426 throw FxTrace.Exception.AsError(new NotImplementedException());
429 public override MethodBase BindToMethod(BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state)
431 throw FxTrace.Exception.AsError(new NotImplementedException());
434 public override object ChangeType(object value, Type type, CultureInfo culture)
436 throw FxTrace.Exception.AsError(new NotImplementedException());
439 public override void ReorderArgumentArray(ref object[] args, object state)
441 throw FxTrace.Exception.AsError(new NotImplementedException());
444 public override MethodBase SelectMethod(BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers)
446 MethodBase[] methodCandidates;
447 this.SelectMethodCalled = true;
449 if (this.genericTypeArguments.Length > 0)
451 // Accept only generic methods which can be successfully instantiated w/ these parameters
452 Collection<MethodBase> methods = new Collection<MethodBase>();
453 foreach (MethodBase method in match)
455 // Must be a MethodInfo because we've already filtered out constructors
456 MethodInfo instantiatedMethod = Instantiate((MethodInfo)method, this.genericTypeArguments);
457 if (instantiatedMethod != null)
459 methods.Add(instantiatedMethod);
462 methodCandidates = methods.ToArray();
466 // Accept only candidates which are already instantiated
467 methodCandidates = match.Where(m => m.ContainsGenericParameters == false).ToArray();
470 if (methodCandidates.Length == 0)
475 // Methods declared on this.declaringType class get top priority as matches
476 Type declaringType = this.declaringType;
477 MethodBase result = null;
480 MethodBase[] methodsDeclaredHere = methodCandidates.Where(mb => mb.DeclaringType == declaringType).ToArray();
481 if (methodsDeclaredHere.Length > 0)
483 // Try to find a match
484 result = FindMatch(methodsDeclaredHere, bindingAttr, types, modifiers);
486 declaringType = declaringType.BaseType;
488 while (declaringType != null && result == null); // short-circuit as soon as we find a match
490 return result; // returns null if no match found
493 MethodBase FindMatch(MethodBase[] methodCandidates, BindingFlags bindingAttr, Type[] types, ParameterModifier[] modifiers)
495 // Try the default binder first. Never gives false positive, but will fail to detect methods w/ parameter array because
496 // it will not expand the formal parameter list when checking against actual parameters.
497 MethodBase result = Type.DefaultBinder.SelectMethod(bindingAttr, methodCandidates, types, modifiers);
499 // Could be false negative, check for parameter array and if so condense it back to an array before re-checking.
502 foreach (MethodBase method in methodCandidates)
504 MethodInfo methodInfo = method as MethodInfo;
505 ParameterInfo[] formalParams = methodInfo.GetParameters();
506 if (MethodResolver.HaveParameterArray(formalParams)) // Check if the last parameter of method is marked w/ "params" attribute
508 Type elementType = formalParams[formalParams.Length - 1].ParameterType.GetElementType();
510 bool allCompatible = true;
511 // There could be more actual parameters than formal parameters, because the formal parameter is a params T'[] for some T'.
512 // So, check that each actual parameter starting at position [formalParams.Length - 1] is compatible with T'.
513 for (int i = formalParams.Length - 1; i < types.Length - 1; i++)
515 if (!TypeHelper.AreTypesCompatible(types[i], elementType))
517 allCompatible = false;
527 // Condense the actual parameter back to an array.
528 Type[] typeArray = new Type[formalParams.Length];
529 for (int i = 0; i < typeArray.Length - 1; i++)
531 typeArray[i] = types[i];
533 typeArray[typeArray.Length - 1] = elementType.MakeArrayType();
535 // Recheck the condensed array
536 MethodBase newFound = Type.DefaultBinder.SelectMethod(bindingAttr, new MethodBase[] { methodInfo }, typeArray, modifiers);
537 if (result != null && newFound != null)
539 string type = newFound.ReflectedType.Name;
540 string name = newFound.Name;
541 string bindingType = bindingAttr == staticBindingFlags ? staticString : instanceString;
542 throw FxTrace.Exception.AsError(new AmbiguousMatchException(SR.DuplicateMethodFound(type, bindingType, name, this.parentActivity.DisplayName)));
554 public override PropertyInfo SelectProperty(BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers)
556 throw FxTrace.Exception.AsError(new NotImplementedException());
560 // Executes method synchronously
561 class SyncMethodExecutor : MethodExecutor
563 MethodInfo syncMethod;
564 Func<object, object[], object> func;
566 public SyncMethodExecutor(CodeActivityMetadata metadata, MethodInfo syncMethod, Activity invokingActivity,
567 Type targetType, InArgument targetObject, Collection<Argument> parameters,
568 RuntimeArgument returnObject,
569 MruCache<MethodInfo, Func<object, object[], object>> funcCache,
570 ReaderWriterLockSlim locker)
571 : base(invokingActivity, targetType, targetObject, parameters, returnObject)
573 Fx.Assert(syncMethod != null, "Must provide syncMethod");
574 this.syncMethod = syncMethod;
575 this.func = MethodCallExpressionHelper.GetFunc(metadata, this.syncMethod, funcCache, locker);
578 public SyncMethodExecutor(SyncMethodExecutor copy, Type targetType, InArgument targetObject, Collection<Argument> parameters,
579 RuntimeArgument returnObject)
580 : base(copy.invokingActivity, targetType, targetObject, parameters, returnObject)
582 this.syncMethod = copy.syncMethod;
583 this.func = copy.func;
586 public bool IsTheSame(MethodInfo newMethod)
588 return !MethodCallExpressionHelper.NeedRetrieve(newMethod, this.syncMethod, this.func);
591 public override bool MethodIsStatic { get { return this.syncMethod.IsStatic; } }
593 protected override IAsyncResult BeginMakeMethodCall(AsyncCodeActivityContext context, object target, AsyncCallback callback, object state)
595 object[] actualParameters = EvaluateAndPackParameters(context, this.syncMethod, false);
597 object result = this.InvokeAndUnwrapExceptions(this.func, target, actualParameters);
599 SetOutArgumentAndReturnValue(context, result, actualParameters);
601 return new CompletedAsyncResult(callback, state);
604 protected override void EndMakeMethodCall(AsyncCodeActivityContext context, IAsyncResult result)
606 CompletedAsyncResult.End(result);
610 // Executes method using paired Begin/End async pattern methods
611 class AsyncPatternMethodExecutor : MethodExecutor
614 MethodInfo beginMethod;
615 MethodInfo endMethod;
616 Func<object, object[], object> beginFunc;
617 Func<object, object[], object> endFunc;
619 public AsyncPatternMethodExecutor(CodeActivityMetadata metadata, MethodInfo beginMethod, MethodInfo endMethod,
620 Activity invokingActivity, Type targetType, InArgument targetObject,
621 Collection<Argument> parameters, RuntimeArgument returnObject,
622 MruCache<MethodInfo, Func<object, object[], object>> funcCache,
623 ReaderWriterLockSlim locker)
624 : base(invokingActivity, targetType, targetObject, parameters, returnObject)
626 Fx.Assert(beginMethod != null && endMethod != null, "Must provide beginMethod and endMethod");
627 this.beginMethod = beginMethod;
628 this.endMethod = endMethod;
629 this.beginFunc = MethodCallExpressionHelper.GetFunc(metadata, beginMethod, funcCache, locker);
630 this.endFunc = MethodCallExpressionHelper.GetFunc(metadata, endMethod, funcCache, locker);
633 public AsyncPatternMethodExecutor(AsyncPatternMethodExecutor copy, Type targetType, InArgument targetObject,
634 Collection<Argument> parameters, RuntimeArgument returnObject)
635 : base(copy.invokingActivity, targetType, targetObject, parameters, returnObject)
637 this.beginMethod = copy.beginMethod;
638 this.endMethod = copy.endMethod;
639 this.beginFunc = copy.beginFunc;
640 this.endFunc = copy.endFunc;
643 public override bool MethodIsStatic { get { return this.beginMethod.IsStatic; } }
645 public bool IsTheSame(MethodInfo newBeginMethod, MethodInfo newEndMethod)
647 return !(MethodCallExpressionHelper.NeedRetrieve(newBeginMethod, this.beginMethod, this.beginFunc)
648 || MethodCallExpressionHelper.NeedRetrieve(newEndMethod, this.endMethod, this.endFunc));
651 protected override IAsyncResult BeginMakeMethodCall(AsyncCodeActivityContext context, object target, AsyncCallback callback, object state)
653 InvokeMethodInstanceData instance = new InvokeMethodInstanceData
655 TargetObject = target,
656 ActualParameters = EvaluateAndPackParameters(context, this.beginMethod, true),
659 int count = instance.ActualParameters.Length;
661 instance.ActualParameters[count - 2] = callback;
662 instance.ActualParameters[count - 1] = state;
663 context.UserState = instance;
665 return (IAsyncResult)this.InvokeAndUnwrapExceptions(this.beginFunc, target, instance.ActualParameters);
668 protected override void EndMakeMethodCall(AsyncCodeActivityContext context, IAsyncResult result)
670 InvokeMethodInstanceData instance = (InvokeMethodInstanceData)context.UserState;
671 instance.ReturnValue = InvokeAndUnwrapExceptions(this.endFunc, instance.TargetObject, new object[] { result });
672 this.SetOutArgumentAndReturnValue(context, instance.ReturnValue, instance.ActualParameters);
676 // Executes method asynchronously on WaitCallback thread.
677 class AsyncWaitCallbackMethodExecutor : MethodExecutor
679 MethodInfo asyncMethod;
680 Func<object, object[], object> asyncFunc;
682 public AsyncWaitCallbackMethodExecutor(CodeActivityMetadata metadata, MethodInfo asyncMethod, Activity invokingActivity,
683 Type targetType, InArgument targetObject, Collection<Argument> parameters,
684 RuntimeArgument returnObject,
685 MruCache<MethodInfo, Func<object, object[], object>> funcCache,
686 ReaderWriterLockSlim locker)
687 : base(invokingActivity, targetType, targetObject, parameters, returnObject)
689 Fx.Assert(asyncMethod != null, "Must provide asyncMethod");
690 this.asyncMethod = asyncMethod;
691 this.asyncFunc = MethodCallExpressionHelper.GetFunc(metadata, asyncMethod, funcCache, locker);
695 public AsyncWaitCallbackMethodExecutor(AsyncWaitCallbackMethodExecutor copy, Type targetType, InArgument targetObject,
696 Collection<Argument> parameters, RuntimeArgument returnObject) :
697 base(copy.invokingActivity, targetType, targetObject, parameters, returnObject)
699 this.asyncMethod = copy.asyncMethod;
700 this.asyncFunc = copy.asyncFunc;
703 public override bool MethodIsStatic { get { return this.asyncMethod.IsStatic; } }
705 public bool IsTheSame(MethodInfo newMethodInfo)
707 return !MethodCallExpressionHelper.NeedRetrieve(newMethodInfo, this.asyncMethod, this.asyncFunc);
710 protected override IAsyncResult BeginMakeMethodCall(AsyncCodeActivityContext context, object target, AsyncCallback callback, object state)
712 InvokeMethodInstanceData instance = new InvokeMethodInstanceData
714 TargetObject = target,
715 ActualParameters = EvaluateAndPackParameters(context, this.asyncMethod, false),
717 return new ExecuteAsyncResult(instance, this, callback, state);
720 protected override void EndMakeMethodCall(AsyncCodeActivityContext context, IAsyncResult result)
722 InvokeMethodInstanceData instance = ExecuteAsyncResult.End(result);
723 if (instance.ExceptionWasThrown)
725 throw FxTrace.Exception.AsError(instance.Exception);
729 this.SetOutArgumentAndReturnValue(context, instance.ReturnValue, instance.ActualParameters);
733 class ExecuteAsyncResult : AsyncResult
735 static Action<object> asyncExecute = new Action<object>(AsyncExecute);
736 InvokeMethodInstanceData instance;
737 AsyncWaitCallbackMethodExecutor executor;
739 public ExecuteAsyncResult(InvokeMethodInstanceData instance, AsyncWaitCallbackMethodExecutor executor, AsyncCallback callback, object state)
740 : base(callback, state)
742 this.instance = instance;
743 this.executor = executor;
744 ActionItem.Schedule(asyncExecute, this);
747 public static InvokeMethodInstanceData End(IAsyncResult result)
749 ExecuteAsyncResult thisPtr = AsyncResult.End<ExecuteAsyncResult>(result);
750 return thisPtr.instance;
753 static void AsyncExecute(object state)
755 ExecuteAsyncResult thisPtr = (ExecuteAsyncResult)state;
756 thisPtr.AsyncExecuteCore();
759 void AsyncExecuteCore()
763 this.instance.ReturnValue = this.executor.InvokeAndUnwrapExceptions(this.executor.asyncFunc, this.instance.TargetObject, this.instance.ActualParameters);
771 this.instance.Exception = e;
772 this.instance.ExceptionWasThrown = true;
774 base.Complete(false);