Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Activities / System / Activities / Statements / MethodExecutor.cs
1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //----------------------------------------------------------------
4
5 namespace System.Activities.Statements
6 {
7     using System;
8     using System.Collections.ObjectModel;
9     using System.Diagnostics.CodeAnalysis;
10     using System.Reflection;
11     using System.Runtime;
12     using System.Linq.Expressions;
13
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
17     {
18         // Used for creating tracing messages w/ DisplayName
19         protected Activity invokingActivity;
20
21         // We may still need to know targetType if we're autocreating targets during ExecuteMethod
22         Type targetType;
23         InArgument targetObject;
24         Collection<Argument> parameters;
25         RuntimeArgument returnObject;
26
27         public MethodExecutor(Activity invokingActivity, Type targetType, InArgument targetObject,
28             Collection<Argument> parameters, RuntimeArgument returnObject)
29         {
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 
34
35             this.invokingActivity = invokingActivity;
36             this.targetType = targetType;
37             this.targetObject = targetObject;
38             this.parameters = parameters;
39             this.returnObject = returnObject;
40         }
41
42         public abstract bool MethodIsStatic { get; }
43
44         protected abstract IAsyncResult BeginMakeMethodCall(AsyncCodeActivityContext context, object target, AsyncCallback callback, object state);
45         protected abstract void EndMakeMethodCall(AsyncCodeActivityContext context, IAsyncResult result);
46
47         static bool HaveParameterArray(ParameterInfo[] parameters)
48         {
49             if (parameters.Length > 0)
50             {
51                 ParameterInfo last = parameters[parameters.Length - 1];
52                 return last.GetCustomAttributes(typeof(ParamArrayAttribute), true).GetLength(0) > 0;
53             }
54             else
55             {
56                 return false;
57             }
58         }
59
60         protected object[] EvaluateAndPackParameters(CodeActivityContext context, MethodInfo method,
61             bool usingAsyncPattern)
62         {
63             ParameterInfo[] formalParameters = method.GetParameters();
64             int formalParamCount = formalParameters.Length;
65             object[] actualParameters = new object[formalParamCount];
66
67             if (usingAsyncPattern)
68             {
69                 formalParamCount -= 2;
70             }
71
72             bool haveParameterArray = HaveParameterArray(formalParameters);
73             for (int i = 0; i < formalParamCount; i++)
74             {
75                 if (i == formalParamCount - 1 && !usingAsyncPattern && haveParameterArray)
76                 {
77                     int paramArrayCount = this.parameters.Count - formalParamCount + 1;
78
79                     // If params are given explicitly, that's okay.
80                     if (paramArrayCount == 1 && TypeHelper.AreTypesCompatible(this.parameters[i].ArgumentType,
81                         formalParameters[i].ParameterType))
82                     {
83                         actualParameters[i] = this.parameters[i].Get<object>(context);
84                     }
85                     else
86                     {
87                         // Otherwise, pack them into an array for the reflection call.
88                         actualParameters[i] =
89                             Activator.CreateInstance(formalParameters[i].ParameterType, paramArrayCount);
90                         for (int j = 0; j < paramArrayCount; j++)
91                         {
92                             ((object[])actualParameters[i])[j] = this.parameters[i + j].Get<object>(context);
93                         }
94                     }
95                     continue;
96                 }
97                 actualParameters[i] = parameters[i].Get<object>(context);
98             }
99
100             return actualParameters;
101         }
102
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)
105         {
106             object targetInstance = null;
107
108             if (!this.MethodIsStatic)
109             {
110                 targetInstance = this.targetObject.Get(context);
111                 if (targetInstance == null)
112                 {
113                     throw FxTrace.Exception.ArgumentNull("TargetObject");
114                 }
115             }
116
117             return BeginMakeMethodCall(context, targetInstance, callback, state); // defer to concrete instance for sync/async variations
118         }
119
120         public void EndExecuteMethod(AsyncCodeActivityContext context, IAsyncResult result)
121         {
122             EndMakeMethodCall(context, result); // defer to concrete instance for sync/async variations
123         }
124
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)
128         {
129             try
130             {
131                 return func(targetInstance, actualParameters);
132             }
133             catch (Exception e)
134             {
135                 if (TD.InvokedMethodThrewExceptionIsEnabled())
136                 {
137                     TD.InvokedMethodThrewException(this.invokingActivity.DisplayName, e.ToString());
138                 }
139                 throw FxTrace.Exception.AsError(e);
140             }
141         }
142
143         public void SetOutArgumentAndReturnValue(ActivityContext context, object state, object[] actualParameters)
144         {
145             for (int index = 0; index < parameters.Count; index++)
146             {
147                 if (parameters[index].Direction != ArgumentDirection.In)
148                 {
149                     parameters[index].Set(context, actualParameters[index]);
150                 }
151             }
152
153             if (this.returnObject != null)
154             {
155                 this.returnObject.Set(context, state);
156             }
157         }
158
159         public void Trace(Activity parent)
160         {
161             if (this.MethodIsStatic)
162             {
163                 if (TD.InvokeMethodIsStaticIsEnabled())
164                 {
165                     TD.InvokeMethodIsStatic(parent.DisplayName);
166                 }
167             }
168             else
169             {
170                 if (TD.InvokeMethodIsNotStaticIsEnabled())
171                 {
172                     TD.InvokeMethodIsNotStatic(parent.DisplayName);
173                 }
174             }
175         }
176
177
178     }
179 }