Skip to content

Commit fe86f77

Browse files
authored
Store MethodInfo when creating an ActivityDefinition (#369)
1 parent 2400644 commit fe86f77

File tree

2 files changed

+81
-27
lines changed

2 files changed

+81
-27
lines changed

src/Temporalio/Activities/ActivityDefinition.cs

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@ private ActivityDefinition(
1919
Type returnType,
2020
IReadOnlyCollection<Type> parameterTypes,
2121
int requiredParameterCount,
22-
Func<object?[], object?> invoker)
22+
Func<object?[], object?> invoker,
23+
MethodInfo? methodInfo)
2324
{
2425
Name = name;
2526
ReturnType = returnType;
2627
ParameterTypes = parameterTypes;
2728
RequiredParameterCount = requiredParameterCount;
2829
this.invoker = invoker;
30+
MethodInfo = methodInfo;
2931
}
3032

3133
/// <summary>
@@ -56,6 +58,11 @@ private ActivityDefinition(
5658
/// </summary>
5759
public bool Dynamic => Name == null;
5860

61+
/// <summary>
62+
/// Gets the <see cref="MethodInfo"/>. Will only have a value if one was used to create this <see cref="ActivityDefinition"/>.
63+
/// </summary>
64+
public MethodInfo? MethodInfo { get; private init; }
65+
5966
/// <summary>
6067
/// Create an activity definition from a delegate. <see cref="Delegate.DynamicInvoke" /> is
6168
/// called on this delegate. The delegate must have an associated method and that method
@@ -89,31 +96,7 @@ public static ActivityDefinition Create(
8996
int requiredParameterCount,
9097
Func<object?[], object?> invoker)
9198
{
92-
// If there is a null name, which means dynamic, there must only be one parameter type
93-
// and it must be varargs IRawValue
94-
if (name == null && (
95-
requiredParameterCount != 1 ||
96-
parameterTypes.SingleOrDefault() != typeof(Converters.IRawValue[])))
97-
{
98-
throw new ArgumentException(
99-
$"Dynamic activity must accept a required array of IRawValue");
100-
}
101-
102-
if (requiredParameterCount > parameterTypes.Count)
103-
{
104-
throw new ArgumentException(
105-
$"Activity {name} has more required parameters than parameters",
106-
nameof(requiredParameterCount));
107-
}
108-
foreach (var parameterType in parameterTypes)
109-
{
110-
if (parameterType.IsByRef)
111-
{
112-
throw new ArgumentException(
113-
$"Activity {name} has disallowed ref/out parameter");
114-
}
115-
}
116-
return new(name, returnType, parameterTypes, requiredParameterCount, invoker);
99+
return Create(name, returnType, parameterTypes, requiredParameterCount, invoker, methodInfo: null);
117100
}
118101

119102
/// <summary>
@@ -136,7 +119,8 @@ public static ActivityDefinition Create(MethodInfo method, Func<object?[], objec
136119
method.ReturnType,
137120
parms.Select(p => p.ParameterType).ToArray(),
138121
parms.Count(p => !p.HasDefaultValue),
139-
parameters => invoker.Invoke(ParametersWithDefaults(parms, parameters)));
122+
parameters => invoker.Invoke(ParametersWithDefaults(parms, parameters)),
123+
method);
140124
}
141125

142126
/// <summary>
@@ -300,5 +284,40 @@ internal static string NameFromMethodForCall(MethodInfo method)
300284
}
301285
return name;
302286
}
287+
288+
private static ActivityDefinition Create(
289+
string? name,
290+
Type returnType,
291+
IReadOnlyCollection<Type> parameterTypes,
292+
int requiredParameterCount,
293+
Func<object?[], object?> invoker,
294+
MethodInfo? methodInfo)
295+
{
296+
// If there is a null name, which means dynamic, there must only be one parameter type
297+
// and it must be varargs IRawValue
298+
if (name == null && (
299+
requiredParameterCount != 1 ||
300+
parameterTypes.SingleOrDefault() != typeof(Converters.IRawValue[])))
301+
{
302+
throw new ArgumentException(
303+
$"Dynamic activity must accept a required array of IRawValue");
304+
}
305+
306+
if (requiredParameterCount > parameterTypes.Count)
307+
{
308+
throw new ArgumentException(
309+
$"Activity {name} has more required parameters than parameters",
310+
nameof(requiredParameterCount));
311+
}
312+
foreach (var parameterType in parameterTypes)
313+
{
314+
if (parameterType.IsByRef)
315+
{
316+
throw new ArgumentException(
317+
$"Activity {name} has disallowed ref/out parameter");
318+
}
319+
}
320+
return new(name, returnType, parameterTypes, requiredParameterCount, invoker, methodInfo);
321+
}
303322
}
304323
}

tests/Temporalio.Tests/Activities/ActivityDefinitionTests.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
namespace Temporalio.Tests.Activities;
22

3+
using System.Reflection;
34
using System.Threading.Tasks;
45
using Temporalio.Activities;
56
using Temporalio.Converters;
@@ -173,6 +174,40 @@ public async Task CreateAll_ClosedGeneric_CanInvoke()
173174
Assert.Equal("some-val", await defn.InvokeAsync(Array.Empty<object?>()));
174175
}
175176

177+
[Fact]
178+
public async Task Create_WithMethodInfo_HasValidMethodInfo()
179+
{
180+
var methodInfo = typeof(ActivityDefinitionTests)
181+
.GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
182+
.Single(mi => mi.Name.Equals(nameof(GoodAct1Async), StringComparison.Ordinal));
183+
184+
var defn = ActivityDefinition.Create(methodInfo, objects => methodInfo!.Invoke(this, objects));
185+
Assert.Equal(methodInfo, defn.MethodInfo);
186+
}
187+
188+
[Fact]
189+
public async Task Create_WithDelegate_HasValidMethodInfo()
190+
{
191+
var methodInfo = typeof(ActivityDefinitionTests)
192+
.GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
193+
.Single(mi => mi.Name.Equals(nameof(GoodAct1Async), StringComparison.Ordinal));
194+
195+
var defn = ActivityDefinition.Create(GoodAct1Async);
196+
Assert.Equal(methodInfo, defn.MethodInfo);
197+
}
198+
199+
[Fact]
200+
public async Task Create_WithLambda_DoesNotHaveValidMethodInfo()
201+
{
202+
var defn = ActivityDefinition.Create(
203+
"some-name",
204+
typeof(int),
205+
new Type[] { typeof(int) },
206+
1,
207+
parameters => ((int)parameters[0]!) + 5);
208+
Assert.Null(defn.MethodInfo);
209+
}
210+
176211
protected static void BadAct1()
177212
{
178213
}

0 commit comments

Comments
 (0)