Skip to content

Commit 087f11b

Browse files
author
Oisin Grehan
committed
initial commit with tests
Signed-off-by: Oisin Grehan <[email protected]>
1 parent 6b49bed commit 087f11b

File tree

2 files changed

+173
-0
lines changed

2 files changed

+173
-0
lines changed

src/Dapr.Actors.Generators/ActorClientGenerator.cs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,62 @@ private static void GenerateActorClientCode(SourceProductionContext context, Act
164164
var actorClientClassTypeParameters = descriptor.InterfaceType.TypeParameters
165165
.Select(x => SyntaxFactory.TypeParameter(x.ToString()));
166166

167+
// Create constraint clauses for type parameters
168+
var constraintClauses = new List<TypeParameterConstraintClauseSyntax>();
169+
170+
// For each type parameter, create constraint clauses based on the interface's constraints
171+
foreach (var typeParam in descriptor.InterfaceType.TypeParameters)
172+
{
173+
if (typeParam.HasReferenceTypeConstraint ||
174+
typeParam.HasValueTypeConstraint ||
175+
typeParam.HasUnmanagedTypeConstraint ||
176+
typeParam.HasNotNullConstraint ||
177+
typeParam.ConstraintTypes.Length > 0)
178+
{
179+
var constraints = new List<TypeParameterConstraintSyntax>();
180+
181+
// Add class/struct constraints
182+
if (typeParam.HasReferenceTypeConstraint)
183+
{
184+
constraints.Add(SyntaxFactory.ClassOrStructConstraint(SyntaxKind.ClassConstraint));
185+
}
186+
else if (typeParam.HasValueTypeConstraint)
187+
{
188+
constraints.Add(SyntaxFactory.ClassOrStructConstraint(SyntaxKind.StructConstraint));
189+
}
190+
191+
// Add unmanaged constraint
192+
if (typeParam.HasUnmanagedTypeConstraint)
193+
{
194+
constraints.Add(SyntaxFactory.TypeConstraint(SyntaxFactory.IdentifierName("unmanaged")));
195+
}
196+
197+
// Add type constraints (e.g., where T : IInterface)
198+
foreach (var constraintType in typeParam.ConstraintTypes)
199+
{
200+
constraints.Add(SyntaxFactory.TypeConstraint(
201+
SyntaxFactory.ParseTypeName(constraintType.ToString())));
202+
}
203+
204+
// Add notnull constraint
205+
if (typeParam.HasNotNullConstraint)
206+
{
207+
constraints.Add(SyntaxFactory.TypeConstraint(SyntaxFactory.IdentifierName("notnull")));
208+
}
209+
210+
// Add new() constraint - must be last
211+
if (typeParam.HasConstructorConstraint)
212+
{
213+
constraints.Add(SyntaxFactory.ConstructorConstraint());
214+
}
215+
216+
constraintClauses.Add(
217+
SyntaxFactory.TypeParameterConstraintClause(
218+
SyntaxFactory.IdentifierName(typeParam.Name),
219+
SyntaxFactory.SeparatedList(constraints)));
220+
}
221+
}
222+
167223
var actorClientClassDeclaration = (actorClientClassTypeParameters.Count() == 0)
168224
? SyntaxFactory.ClassDeclaration(descriptor.ClientTypeName)
169225
.WithModifiers(SyntaxFactory.TokenList(actorClientClassModifiers))
@@ -174,6 +230,7 @@ private static void GenerateActorClientCode(SourceProductionContext context, Act
174230
: SyntaxFactory.ClassDeclaration(descriptor.ClientTypeName)
175231
.WithModifiers(SyntaxFactory.TokenList(actorClientClassModifiers))
176232
.WithTypeParameterList(SyntaxFactory.TypeParameterList(SyntaxFactory.SeparatedList(actorClientClassTypeParameters)))
233+
.WithConstraintClauses(SyntaxFactory.List(constraintClauses)) // Add constraint clauses to the class
177234
.WithMembers(SyntaxFactory.List(actorMembers))
178235
.WithBaseList(SyntaxFactory.BaseList(
179236
SyntaxFactory.Token(SyntaxKind.ColonToken),

test/Dapr.Actors.Generators.Test/ActorClientGeneratorTests.cs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,4 +877,120 @@ public interface ITestActor
877877

878878
await test.RunAsync();
879879
}
880+
881+
[Fact]
882+
public async Task TestGenericWithConstraints()
883+
{
884+
var originalSource = @"
885+
using Dapr.Actors.Generators;
886+
using System.Threading.Tasks;
887+
888+
namespace Test
889+
{
890+
public interface ITrait
891+
{
892+
string GetName();
893+
}
894+
895+
[GenerateActorClient]
896+
public interface ITestActor<TTrait> where TTrait : ITrait
897+
{
898+
Task<bool> SetTrait(TTrait trait);
899+
Task<TTrait> GetTrait(string name);
900+
}
901+
}";
902+
903+
var generatedSource = @"// <auto-generated/>
904+
#nullable enable
905+
namespace Test
906+
{
907+
public sealed class TestActorClient<TTrait> : Test.ITestActor<TTrait> where TTrait : Test.ITrait
908+
{
909+
private readonly Dapr.Actors.Client.ActorProxy actorProxy;
910+
public TestActorClient(Dapr.Actors.Client.ActorProxy actorProxy)
911+
{
912+
if (actorProxy is null)
913+
{
914+
throw new System.ArgumentNullException(nameof(actorProxy));
915+
}
916+
917+
this.actorProxy = actorProxy;
918+
}
919+
920+
public System.Threading.Tasks.Task<TTrait> GetTrait(string name)
921+
{
922+
return this.actorProxy.InvokeMethodAsync<string, TTrait>(""GetTrait"", name);
923+
}
924+
925+
public System.Threading.Tasks.Task<bool> SetTrait(TTrait trait)
926+
{
927+
return this.actorProxy.InvokeMethodAsync<TTrait, bool>(""SetTrait"", trait);
928+
}
929+
}
930+
}";
931+
932+
await CreateTest(originalSource, "Test.TestActorClient.g.cs", generatedSource).RunAsync();
933+
}
934+
935+
[Fact]
936+
public async Task TestGenericWithMultipleTypeParametersAndConstraints()
937+
{
938+
var originalSource = @"
939+
using Dapr.Actors.Generators;
940+
using System.Threading.Tasks;
941+
942+
namespace Test
943+
{
944+
public interface ITrait
945+
{
946+
string GetName();
947+
}
948+
949+
public interface IValidator<T>
950+
{
951+
bool Validate(T item);
952+
}
953+
954+
[GenerateActorClient]
955+
public interface ITestActor<TTrait, TValidator>
956+
where TTrait : ITrait, new()
957+
where TValidator : class, IValidator<TTrait>
958+
{
959+
Task<bool> SetTrait(TTrait trait);
960+
Task<TTrait> GetValidatedTrait(string name);
961+
}
962+
}";
963+
964+
var generatedSource = @"// <auto-generated/>
965+
#nullable enable
966+
namespace Test
967+
{
968+
public sealed class TestActorClient<TTrait, TValidator> : Test.ITestActor<TTrait, TValidator> where TTrait : Test.ITrait, new()
969+
where TValidator : class, Test.IValidator<TTrait>
970+
{
971+
private readonly Dapr.Actors.Client.ActorProxy actorProxy;
972+
public TestActorClient(Dapr.Actors.Client.ActorProxy actorProxy)
973+
{
974+
if (actorProxy is null)
975+
{
976+
throw new System.ArgumentNullException(nameof(actorProxy));
977+
}
978+
979+
this.actorProxy = actorProxy;
980+
}
981+
982+
public System.Threading.Tasks.Task<TTrait> GetValidatedTrait(string name)
983+
{
984+
return this.actorProxy.InvokeMethodAsync<string, TTrait>(""GetValidatedTrait"", name);
985+
}
986+
987+
public System.Threading.Tasks.Task<bool> SetTrait(TTrait trait)
988+
{
989+
return this.actorProxy.InvokeMethodAsync<TTrait, bool>(""SetTrait"", trait);
990+
}
991+
}
992+
}";
993+
994+
await CreateTest(originalSource, "Test.TestActorClient.g.cs", generatedSource).RunAsync();
995+
}
880996
}

0 commit comments

Comments
 (0)