Skip to content

Commit 7ad1b93

Browse files
committed
Added GenerateDelegateAttribute to reduce boiler plate code
1 parent a668d96 commit 7ad1b93

File tree

32 files changed

+2779
-6
lines changed

32 files changed

+2779
-6
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<Copyright>(c) $([System.DateTime]::Now.Year), Pawel Gerr. All rights reserved.</Copyright>
5-
<VersionPrefix>8.4.1</VersionPrefix>
5+
<VersionPrefix>8.5.0</VersionPrefix>
66
<Authors>Pawel Gerr</Authors>
77
<GenerateDocumentationFile>true</GenerateDocumentationFile>
88
<PackageProjectUrl>https://github.com/PawelGerr/Thinktecture.Runtime.Extensions</PackageProjectUrl>

docs

Submodule docs updated from dfe34a7 to 4a74d2a

samples/Thinktecture.Runtime.Extensions.Samples/SmartEnums/SalesCsvImporterType.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@ public partial class SalesCsvImporterType
1212
public int ArticleIdIndex { get; }
1313
public int VolumeIndex { get; }
1414

15-
private readonly Func<CsvReader, DateTime> _getDateTime;
16-
17-
public DateTime GetDateTime(CsvReader csvReader) => _getDateTime(csvReader);
15+
[GenerateDelegate]
16+
public partial DateTime GetDateTime(CsvReader csvReader);
1817

1918
private static DateTime GetDateTimeForDaily(CsvReader csvReader)
2019
{
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
namespace Thinktecture.CodeAnalysis;
2+
3+
public sealed class DelegateMethodState : IEquatable<DelegateMethodState>, IHashCodeComputable
4+
{
5+
public Accessibility Accessibility { get; }
6+
public string MethodName { get; }
7+
public string? ReturnType { get; }
8+
public IReadOnlyList<ParameterState> Parameters { get; }
9+
public string ArgumentName { get; }
10+
11+
public DelegateMethodState(
12+
Accessibility accessibility,
13+
string methodName,
14+
string? returnType,
15+
IReadOnlyList<ParameterState> parameters)
16+
{
17+
Accessibility = accessibility;
18+
MethodName = methodName;
19+
ReturnType = returnType;
20+
Parameters = parameters;
21+
ArgumentName = methodName.MakeArgumentName();
22+
}
23+
24+
public bool Equals(DelegateMethodState? other)
25+
{
26+
if (other is null)
27+
return false;
28+
if (ReferenceEquals(this, other))
29+
return true;
30+
31+
return Accessibility == other.Accessibility
32+
&& MethodName == other.MethodName
33+
&& ReturnType == other.ReturnType
34+
&& Parameters.SequenceEqual(other.Parameters);
35+
}
36+
37+
public override bool Equals(object? obj)
38+
{
39+
return obj is DelegateMethodState other && Equals(other);
40+
}
41+
42+
public override int GetHashCode()
43+
{
44+
unchecked
45+
{
46+
var hashCode = (int)Accessibility;
47+
hashCode = (hashCode * 397) ^ MethodName.GetHashCode();
48+
hashCode = (hashCode * 397) ^ ReturnType?.GetHashCode() ?? 0;
49+
hashCode = (hashCode * 397) ^ Parameters.ComputeHashCode();
50+
return hashCode;
51+
}
52+
}
53+
54+
public sealed class ParameterState : IEquatable<ParameterState>, IHashCodeComputable
55+
{
56+
public string Name { get; }
57+
public string Type { get; }
58+
59+
public ParameterState(string name, string type)
60+
{
61+
Name = name;
62+
Type = type;
63+
}
64+
65+
public override bool Equals(object? obj)
66+
{
67+
return obj is ParameterState other && Equals(other);
68+
}
69+
70+
public bool Equals(ParameterState? other)
71+
{
72+
if (other is null)
73+
return false;
74+
75+
if (ReferenceEquals(this, other))
76+
return true;
77+
78+
return Name == other.Name
79+
&& Type == other.Type;
80+
}
81+
82+
public override int GetHashCode()
83+
{
84+
unchecked
85+
{
86+
return (Name.GetHashCode() * 397) ^ Type.GetHashCode();
87+
}
88+
}
89+
}
90+
}

src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/SmartEnums/EnumSourceGeneratorState.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public sealed class EnumSourceGeneratorState : ITypeInformation, IEquatable<Enum
2424

2525
public EnumItems Items { get; }
2626
public IReadOnlyList<InstanceMemberInfo> AssignableInstanceFieldsAndProperties { get; }
27+
public IReadOnlyList<DelegateMethodState> DelegateMethods { get; }
2728

2829
public EnumSourceGeneratorState(
2930
TypedMemberStateFactory factory,
@@ -54,6 +55,7 @@ public EnumSourceGeneratorState(
5455
BaseType = type.GetBaseType(factory);
5556
Items = new EnumItems(type.GetEnumItems());
5657
AssignableInstanceFieldsAndProperties = type.GetAssignableFieldsAndPropertiesAndCheckForReadOnly(factory, true, false, cancellationToken).ToList();
58+
DelegateMethods = type.GetDelegateMethods();
5759
}
5860

5961
public override bool Equals(object? obj)
@@ -80,7 +82,8 @@ public bool Equals(EnumSourceGeneratorState? other)
8082
&& Equals(BaseType, other.BaseType)
8183
&& Items.Equals(other.Items)
8284
&& AssignableInstanceFieldsAndProperties.SequenceEqual(other.AssignableInstanceFieldsAndProperties)
83-
&& ContainingTypes.SequenceEqual(other.ContainingTypes);
85+
&& ContainingTypes.SequenceEqual(other.ContainingTypes)
86+
&& DelegateMethods.SequenceEqual(other.DelegateMethods);
8487
}
8588

8689
public override int GetHashCode()
@@ -100,6 +103,7 @@ public override int GetHashCode()
100103
hashCode = (hashCode * 397) ^ Items.GetHashCode();
101104
hashCode = (hashCode * 397) ^ AssignableInstanceFieldsAndProperties.ComputeHashCode();
102105
hashCode = (hashCode * 397) ^ ContainingTypes.ComputeHashCode();
106+
hashCode = (hashCode * 397) ^ DelegateMethods.ComputeHashCode();
103107

104108
return hashCode;
105109
}

src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/SmartEnums/SmartEnumCodeGenerator.cs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,15 @@ private void GenerateEnum(CancellationToken cancellationToken)
156156

157157
cancellationToken.ThrowIfCancellationRequested();
158158

159+
if (_state.DelegateMethods.Count > 0)
160+
{
161+
foreach (var method in _state.DelegateMethods)
162+
{
163+
_sb.Append(@"
164+
private readonly ").AppendDelegateType(method).Append(" _").Append(method.ArgumentName).Append(";");
165+
}
166+
}
167+
159168
GenerateConstructors();
160169

161170
if (_state.KeyMember is not null)
@@ -209,6 +218,8 @@ public override int GetHashCode()
209218
if (_state.KeyMember is not null && !_state.Settings.SkipToString)
210219
GenerateToString(_state.KeyMember);
211220

221+
GenerateDelegateMethods();
222+
212223
var hasSaneNumberOfItems = _state.Items.Count < 1000;
213224

214225
if (_state.Settings.SwitchMethods != SwitchMapMethodsGeneration.None && generateIndexBasedSwitchMap && hasSaneNumberOfItems)
@@ -255,6 +266,40 @@ public override int GetHashCode()
255266
}");
256267
}
257268

269+
private void GenerateDelegateMethods()
270+
{
271+
foreach (var method in _state.DelegateMethods)
272+
{
273+
_sb.Append(@"
274+
275+
").AppendAccessibility(method.Accessibility).Append(" partial ").Append(method.ReturnType ?? "void").Append(" ").Append(method.MethodName).Append("(");
276+
277+
for (var i = 0; i < method.Parameters.Count; i++)
278+
{
279+
if (i > 0)
280+
_sb.Append(", ");
281+
282+
var param = method.Parameters[i];
283+
_sb.Append(param.Type).Append(" ").Append(param.Name);
284+
}
285+
286+
_sb.Append(@")
287+
{
288+
return _").Append(method.ArgumentName).Append("(");
289+
290+
for (var i = 0; i < method.Parameters.Count; i++)
291+
{
292+
if (i > 0)
293+
_sb.Append(", ");
294+
295+
_sb.Append(method.Parameters[i].Name);
296+
}
297+
298+
_sb.Append(@");
299+
}");
300+
}
301+
}
302+
258303
private void GenerateToString(KeyMemberState keyProperty)
259304
{
260305
_sb.Append(@"
@@ -1555,6 +1600,16 @@ private void GenerateConstructor(
15551600
").AppendTypeFullyQualified(member).Append(" ").AppendEscaped(member.ArgumentName);
15561601
}
15571602

1603+
if (_state.DelegateMethods.Count > 0)
1604+
{
1605+
foreach (var method in _state.DelegateMethods)
1606+
{
1607+
_sb.Append(",");
1608+
_sb.Append(@"
1609+
").AppendDelegateType(method).Append(" ").AppendEscaped(method.ArgumentName);
1610+
}
1611+
}
1612+
15581613
_sb.Append(@")
15591614
: this(");
15601615

@@ -1572,6 +1627,14 @@ private void GenerateConstructor(
15721627
_sb.Append(", ").AppendEscaped(ctorArgs[i].ArgumentName);
15731628
}
15741629

1630+
if (_state.DelegateMethods.Count > 0)
1631+
{
1632+
foreach (var method in _state.DelegateMethods)
1633+
{
1634+
_sb.Append(", ").AppendEscaped(method.ArgumentName);
1635+
}
1636+
}
1637+
15751638
_sb.Append(@")
15761639
{
15771640
}");
@@ -1611,6 +1674,16 @@ private void GenerateConstructor(
16111674
").AppendTypeFullyQualified(member).Append(" ").AppendEscaped(member.ArgumentName);
16121675
}
16131676

1677+
if (_state.DelegateMethods.Count > 0)
1678+
{
1679+
foreach (var method in _state.DelegateMethods)
1680+
{
1681+
_sb.Append(",");
1682+
_sb.Append(@"
1683+
").AppendDelegateType(method).Append(" ").AppendEscaped(method.ArgumentName);
1684+
}
1685+
}
1686+
16141687
_sb.Append(")");
16151688

16161689
if (baseCtorArgs.Count > 0)
@@ -1689,6 +1762,15 @@ private void GenerateConstructor(
16891762
this.").Append(memberInfo.Name).Append(" = ").AppendEscaped(memberInfo.ArgumentName).Append(";");
16901763
}
16911764

1765+
if (_state.DelegateMethods.Count > 0)
1766+
{
1767+
foreach (var method in _state.DelegateMethods)
1768+
{
1769+
_sb.Append(@"
1770+
this._").Append(method.ArgumentName).Append(" = ").AppendEscaped(method.ArgumentName).Append(";");
1771+
}
1772+
}
1773+
16921774
if (_state.KeyMember is not null)
16931775
{
16941776
_sb.Append(@"

src/Thinktecture.Runtime.Extensions.SourceGenerator/Extensions/StringBuilderExtensions.cs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,32 @@ public static StringBuilder AppendAccessModifier(
8282
return sb;
8383
}
8484

85+
public static StringBuilder AppendAccessibility(
86+
this StringBuilder sb,
87+
Accessibility accessibility)
88+
{
89+
switch (accessibility)
90+
{
91+
case Accessibility.Private:
92+
sb.Append("private");
93+
break;
94+
case Accessibility.ProtectedAndInternal:
95+
sb.Append("protected internal");
96+
break;
97+
case Accessibility.Protected:
98+
sb.Append("protected");
99+
break;
100+
case Accessibility.Internal:
101+
sb.Append("internal");
102+
break;
103+
case Accessibility.Public:
104+
sb.Append("public");
105+
break;
106+
}
107+
108+
return sb;
109+
}
110+
85111
public static StringBuilder RenderArguments(
86112
this StringBuilder sb,
87113
IReadOnlyList<InstanceMemberInfo> members,
@@ -298,4 +324,42 @@ public static StringBuilder RenderContainingTypesEnd(
298324

299325
return sb;
300326
}
327+
328+
public static StringBuilder AppendDelegateType(
329+
this StringBuilder sb,
330+
DelegateMethodState method)
331+
{
332+
var isFunc = method.ReturnType is not null;
333+
334+
if (isFunc)
335+
{
336+
sb.Append("global::System.Func");
337+
}
338+
else
339+
{
340+
sb.Append("global::System.Action");
341+
}
342+
343+
if (method.Parameters.Count == 0)
344+
{
345+
return isFunc
346+
? sb.Append("<").Append(method.ReturnType).Append(">")
347+
: sb;
348+
}
349+
350+
sb.Append("<");
351+
352+
for (var i = 0; i < method.Parameters.Count; i++)
353+
{
354+
if (i > 0)
355+
sb.Append(", ");
356+
357+
sb.Append(method.Parameters[i].Type);
358+
}
359+
360+
if (isFunc)
361+
sb.Append(", ").Append(method.ReturnType);
362+
363+
return sb.Append(">");
364+
}
301365
}

0 commit comments

Comments
 (0)