1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //----------------------------------------------------------------
5 namespace System.Activities.Statements
8 using System.Collections.ObjectModel;
9 using System.Diagnostics.CodeAnalysis;
10 using System.Reflection;
12 using System.Linq.Expressions;
14 // Inverted Template Method pattern. MethodExecutor is the base class for executing a method; created by MethodResolver.
15 // Private concrete implementations are created by MethodResolver, but this is the "public" API used by InvokeMethod.
16 abstract class MethodExecutor
18 // Used for creating tracing messages w/ DisplayName
19 protected Activity invokingActivity;
21 // We may still need to know targetType if we're autocreating targets during ExecuteMethod
23 InArgument targetObject;
24 Collection<Argument> parameters;
25 RuntimeArgument returnObject;
27 public MethodExecutor(Activity invokingActivity, Type targetType, InArgument targetObject,
28 Collection<Argument> parameters, RuntimeArgument returnObject)
30 Fx.Assert(invokingActivity != null, "Must provide invokingActivity");
31 Fx.Assert(targetType != null || (targetObject != null), "Must provide targetType or targetObject");
32 Fx.Assert(parameters != null, "Must provide parameters");
33 // returnObject is optional
35 this.invokingActivity = invokingActivity;
36 this.targetType = targetType;
37 this.targetObject = targetObject;
38 this.parameters = parameters;
39 this.returnObject = returnObject;
42 public abstract bool MethodIsStatic { get; }
44 protected abstract IAsyncResult BeginMakeMethodCall(AsyncCodeActivityContext context, object target, AsyncCallback callback, object state);
45 protected abstract void EndMakeMethodCall(AsyncCodeActivityContext context, IAsyncResult result);
47 static bool HaveParameterArray(ParameterInfo[] parameters)
49 if (parameters.Length > 0)
51 ParameterInfo last = parameters[parameters.Length - 1];
52 return last.GetCustomAttributes(typeof(ParamArrayAttribute), true).GetLength(0) > 0;
60 protected object[] EvaluateAndPackParameters(CodeActivityContext context, MethodInfo method,
61 bool usingAsyncPattern)
63 ParameterInfo[] formalParameters = method.GetParameters();
64 int formalParamCount = formalParameters.Length;
65 object[] actualParameters = new object[formalParamCount];
67 if (usingAsyncPattern)
69 formalParamCount -= 2;
72 bool haveParameterArray = HaveParameterArray(formalParameters);
73 for (int i = 0; i < formalParamCount; i++)
75 if (i == formalParamCount - 1 && !usingAsyncPattern && haveParameterArray)
77 int paramArrayCount = this.parameters.Count - formalParamCount + 1;
79 // If params are given explicitly, that's okay.
80 if (paramArrayCount == 1 && TypeHelper.AreTypesCompatible(this.parameters[i].ArgumentType,
81 formalParameters[i].ParameterType))
83 actualParameters[i] = this.parameters[i].Get<object>(context);
87 // Otherwise, pack them into an array for the reflection call.
89 Activator.CreateInstance(formalParameters[i].ParameterType, paramArrayCount);
90 for (int j = 0; j < paramArrayCount; j++)
92 ((object[])actualParameters[i])[j] = this.parameters[i + j].Get<object>(context);
97 actualParameters[i] = parameters[i].Get<object>(context);
100 return actualParameters;
103 [SuppressMessage(FxCop.Category.Usage, FxCop.Rule.InstantiateArgumentExceptionsCorrectly, Justification = "TargetObject is a parameter to InvokeMethod, rather than this specific method.")]
104 public IAsyncResult BeginExecuteMethod(AsyncCodeActivityContext context, AsyncCallback callback, object state)
106 object targetInstance = null;
108 if (!this.MethodIsStatic)
110 targetInstance = this.targetObject.Get(context);
111 if (targetInstance == null)
113 throw FxTrace.Exception.ArgumentNull("TargetObject");
117 return BeginMakeMethodCall(context, targetInstance, callback, state); // defer to concrete instance for sync/async variations
120 public void EndExecuteMethod(AsyncCodeActivityContext context, IAsyncResult result)
122 EndMakeMethodCall(context, result); // defer to concrete instance for sync/async variations
125 [SuppressMessage("Reliability", "Reliability108:IsFatalRule",
126 Justification = "We need throw out all exceptions from method invocation.")]
127 internal object InvokeAndUnwrapExceptions(Func<object, object[], object> func, object targetInstance, object[] actualParameters)
131 return func(targetInstance, actualParameters);
135 if (TD.InvokedMethodThrewExceptionIsEnabled())
137 TD.InvokedMethodThrewException(this.invokingActivity.DisplayName, e.ToString());
139 throw FxTrace.Exception.AsError(e);
143 public void SetOutArgumentAndReturnValue(ActivityContext context, object state, object[] actualParameters)
145 for (int index = 0; index < parameters.Count; index++)
147 if (parameters[index].Direction != ArgumentDirection.In)
149 parameters[index].Set(context, actualParameters[index]);
153 if (this.returnObject != null)
155 this.returnObject.Set(context, state);
159 public void Trace(Activity parent)
161 if (this.MethodIsStatic)
163 if (TD.InvokeMethodIsStaticIsEnabled())
165 TD.InvokeMethodIsStatic(parent.DisplayName);
170 if (TD.InvokeMethodIsNotStaticIsEnabled())
172 TD.InvokeMethodIsNotStatic(parent.DisplayName);