-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfeed.rss
1032 lines (967 loc) · 67.7 KB
/
feed.rss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
<channel>
<title />
<link>https://alwaysdeveloping.net/</link>
<description>always learning | always growing</description>
<copyright>Copyright © 2023</copyright>
<pubDate>Thu, 21 Sep 2023 03:35:48 GMT</pubDate>
<lastBuildDate>Thu, 21 Sep 2023 03:35:48 GMT</lastBuildDate>
<item>
<title>Introducing the Source Generator Toolkit</title>
<link>https://alwaysdeveloping.net/p/2023-07-source-gen-toolkit</link>
<description>always learning | always growing</description>
<guid>https://alwaysdeveloping.net/p/2023-07-source-gen-toolkit</guid>
<pubDate>Mon, 24 Jul 2023 03:00:00 GMT</pubDate>
<content:encoded><h2 id="introduction">Introduction</h2>
<p>Ever wanted to try leverage <em>Roslyn Source Generators</em>, but the process seemed too complex? The <a href="https://www.nuget.org/packages/SourceGeneratorToolkit"><code>Source Generator Toolkit</code></a> aims to make this process easier, but providing two pieces of core functionality:</p>
<ul>
<li><code>Code Generation</code>: this can be leveraged in conjunction with the Roslyn Source Generator process, or standalone and allows for the easy generation of C# source code using a <em>fluent builder pattern</em>.</li>
<li><code>Code Qualification</code>: this is leverage as part of the Roslyn Source Generator process, and make the process of <em>determining if a syntax node qualifies for source generation</em> easier and more stream-lined.</li>
</ul>
<hr />
<h2 id="reason-for-the-library">Reason for the library</h2>
<p>The main aim of the code generation functionality of the library is to <code>remove as much of the hard-coded C# strings required when creating a source generator as possible</code>. Some hard-coded <em>strings of code</em> will still be required for specific logic, however the main scaffolding of the classes, methods etc can be done through the library using a <em>fluent builder pattern</em>. This pattern makes it easy to build up the source code logically, with each component building on the previous one.</p>
<p>While the initial idea was for the <code>Source Generator Toolkit</code> to be used with <em>Roslyn Source Generators</em>, the code generation functionality can be leveraged outside of this process to just generate a string representation of C# code.</p>
<p>When creating a <em>Roslyn Source Generators</em> in most cases, before source code is generated, <em>qualification checks</em> need to be performed to determine <em>if</em> the source code should be generated, and to determine the values to be used in the generated code. Here the aim of the <code>Source Generator Toolkit</code> was to make working the the syntax nodes and syntax tree as easy as possible, by <code>providing a variety of extension methods for qualification checks performed on syntax nodes</code>. The qualification check functionality is done, again, through a <em>fluent builder</em> which allows for the qualification check to logically be built up - easily to maintain and easier to understand.</p>
<hr />
<h2 id="generating-code-outside-of-the-roslyn-source-generator-process">Generating Code - outside of the Roslyn Source Generator process</h2>
<p>First we'll look at how to generate c# source code, outside of the Roslyn Source Generator process.</p>
<p>The static <code>SourceGenerator</code> class is the starting point for building up the source code. No actual <em>true c# code</em> is generated here - just a <strong>formatted string representation of c# code</strong>:</p>
<pre><code class="language-csharp">var strCode = SourceGenerator.GenerateSource(gen =&gt;
{
gen.WithFile(&quot;file1&quot;, file =&gt;
{
file.WithNamespace(&quot;SampleNamespace&quot;, ns =&gt;
{
ns.WithClass(&quot;SampleClass&quot;, cls =&gt; { });
});
});
});
</code></pre>
<p>The string output of the above being (the value of <code>strCode</code>):</p>
<pre><code class="language-csharp">namespace SampleNamespace
{
[System.CodeDom.Compiler.GeneratedCode(&quot;SourceGeneratorToolkit&quot;, &quot;0.0.0.1&quot;)]
class SampleClass
{
}
}
</code></pre>
<p>As you can see from this simple example, defining the code is easy:</p>
<ul>
<li>start with a &quot;file&quot; (in this case, it is an &quot;in-memory&quot; file which will hold the defined c# code)</li>
<li>the file contains a single <code>namespace</code>, <em>SampleNamespace</em></li>
<li>the namespace contains a single <code>class</code>, <em>SampleClass</em></li>
</ul>
<p>Each component is defined with its required properties (such as name in the above examples), and then an optional builder Action to define its child components.</p>
<hr />
<h2 id="generating-code-roslyn-source-generator-process-without-isyntaxreceiver">Generating Code - Roslyn Source Generator process (without ISyntaxReceiver)</h2>
<p>Next, we look at leveraging the <code>Source Generator Toolkit</code> as <em>part of the Roslyn Source Generator process</em> - but when the <code>ISyntaxReceiver</code> is not used. This use case is for the scenarios when the generated source code must always be output and is not reliant on a <em>qualification check</em> being done.</p>
<p>When used in conjunction with a Source Generator, the <code>GenerateSource</code> extension method on the <code>GeneratorExecutionContext</code> class can be leveraged.</p>
<p>The below example shows how to generate source code <code>without any information from a SyntaxReceiver</code> - see further down on how the <code>Source Generator Toolkit</code> can be used to generate code in conjunction with a <code>ISyntaxReceiver</code> implementation.</p>
<pre><code class="language-csharp">// a ISourceGenerator implementation
public class SampleGenerator : ISourceGenerator
{
public void Execute(GeneratorExecutionContext context)
{
context.GenerateSource(&quot;file1&quot;, fileBuilder =&gt;
{
fileBuilder.WithNamespace(&quot;SampleNamespace&quot;, nsBuilder =&gt;
{
ns.WithClass(&quot;SampleClass&quot;, cls =&gt; { });
});
});
}
public void Initialize(GeneratorInitializationContext context)
{
// no ISyntaxReceiver implementation registered here
}
}
</code></pre>
<p>In the case of a Source Generator, an actual file named <code>file1.cs</code> will be output as part of the generation process.</p>
<p>The output content of the file will be the same as in the previous example:</p>
<pre><code class="language-csharp">namespace SampleNamespace
{
[System.CodeDom.Compiler.GeneratedCode(&quot;SourceGeneratorToolkit&quot;, &quot;0.0.0.1&quot;)]
class SampleClass
{
}
}
</code></pre>
<p>The <em>fluent builder pattern</em> is leveraged to build up the source code in exactly the same manner as in the previous example above.</p>
<hr />
<h2 id="generating-code-configuration">Generating Code - Configuration</h2>
<p>There is optional configuration which can be specified when generating the code using either of the above two methods (when calling the <code>GenerateSource</code> method). If no configuration is specified, the default configuration is used.</p>
<table>
<thead>
<tr>
<th>Configuration Name</th>
<th>Description</th>
<th>Default Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>OutputGeneratedCodeAttribute</td>
<td>Flag to indicate if the <code>System.CodeDom.Compiler.GeneratedCode</code> attribute should be output with generated code. This attribute is used as an indicator to various tools that the code was auto generated</td>
<td>true</td>
</tr>
<tr>
<td>OutputDebuggerStepThroughAttribute</td>
<td>Flag to indicate if the <code>System.Diagnostics.DebuggerStepThrough</code> attribute should be output with generated code. When set to true, this attribute allows stepping into the generated code when debugging</td>
<td>false</td>
</tr>
</tbody>
</table>
<hr />
<h2 id="code-qualification-roslyn-source-generator-process-with-isyntaxreceiver-implementation">Code Qualification - Roslyn Source Generator process (with ISyntaxReceiver implementation)</h2>
<p>When using the .NET Roslyn Source Generator process, the actual <em>generation</em> of the source is only one step of the process - the other step is determining <em>if the source should be generated in the first place</em>. This <em>qualification check</em> is done in the <code>OnVisitSyntaxNode</code> method of the <code>ISyntaxReceiver</code> implementation.</p>
<p>The <code>OnVisitSyntaxNode</code> method takes a <code>SyntaxNode</code> as an argument (this is part of the normal Roslyn Source Generator process) - the <code>Source Generator Toolkit</code> provides an extension method (<code>NodeQualifiesWhen</code>) which accepts a <em>qualification builder</em> which is used to determine if the SyntaxNode qualifies to have source code generated.</p>
<p>The <em>fluent builder</em> pattern is again used to build up the qualification check for for the syntax:</p>
<pre><code class="language-csharp">class SampleClassSyntaxReceiver : ISyntaxReceiver
{
public List&lt;SyntaxReceiverResult&gt; Results { get; set; } = new List&lt;SyntaxReceiverResult&gt;();
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{
syntaxNode.NodeQualifiesWhen(Results, node =&gt;
{
node.IsClass(c =&gt; c
.WithName(&quot;SampleClass&quot;)
.IsNotStatic()
.IsPublic()
.Implements(&quot;ISerializable&quot;)
);
});
}
}
</code></pre>
<p>In the above example, if the qualification checks determines the node is:</p>
<ul>
<li>a class named <code>SampleClass</code></li>
<li>which is public</li>
<li>and not static</li>
<li>and also implements <code>ISerializable</code></li>
</ul>
<p>then the specific <code>SyntaxNode</code> qualifies, and the <em>Results</em> list will be populated and passed to the <em>Execute</em> method of the generator.</p>
<p>A most complex, but <em>less practical</em> example:</p>
<pre><code class="language-csharp">syntaxNode.NodeQualifiesWhen(Results, node =&gt;
{
node.IsClass(c =&gt; c
.WithName(&quot;SampleClass&quot;)
.IsNotStatic()
.IsNotPrivateProtected()
.IsPublic()
.Implements(&quot;ISerializable&quot;)
// the class must have the Obsolete attribute
.WithAttribute(a =&gt;
{
a.WithName(&quot;Obsolete&quot;);
})
.WithMethod(m =&gt;
{
// the class must have a method called &quot;SampleMethod&quot;
m.WithName(&quot;SampleMethod&quot;)
// which is async
.IsAsync()
// with the Obsolete attribute with a parameter in position 1 supplied
.WithAttribute(a =&gt;
{
a.WithName(&quot;Obsolete&quot;)
.WithArgument(arg =&gt;
{
arg.WithPosition(1);
});
})
// method must have a return type of Task
.WithReturnType(typeof(Task));
})
);
});
</code></pre>
<hr />
<h2 id="code-generation-roslyn-source-generator-process-with-isyntaxreceiver-implementation">Code Generation - Roslyn Source Generator process (with ISyntaxReceiver implementation)</h2>
<p>When generating code based on the output of the <em>qualification process</em> (<code>OnVisitSyntaxNode</code> method in the <code>ISyntaxReceiver</code> implementation, shown above), the <code>Results</code> list is populated with the qualifying <code>SyntaxNode(s)</code>, and passed to the <code>Execute</code> method of the <code>ISourceGenerator</code> implementation.</p>
<p>Using the same <code>ISyntaxReceiver</code> implementation as above:</p>
<pre><code class="language-csharp">class SampleClassSyntaxReceiver : ISyntaxReceiver
{
public List&lt;SyntaxReceiverResult&gt; Results { get; set; } = new List&lt;SyntaxReceiverResult&gt;();
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{
syntaxNode.NodeQualifiesWhen(Results, node =&gt;
{
node.IsClass(c =&gt; c
.WithName(&quot;SampleClass&quot;)
.IsNotStatic()
.IsPublic()
.Implements(&quot;ISerializable&quot;)
);
});
}
}
</code></pre>
<p>For each qualifying node, the <code>Results</code> property is populated with the qualifying <code>SyntaxNode</code> in question.</p>
<p>Below is a sample of a <code>ISourceGenerator</code> which used the <em>Results</em> output from the <code>OnVisitSyntaxNode</code> method to generate source code:</p>
<pre><code class="language-csharp">[Generator]
public class PartialMethodGenerator : ISourceGenerator
{
public void Initialize(GeneratorInitializationContext context)
{
// Register our custom syntax receiver
context.RegisterForSyntaxNotifications(() =&gt; new PartialClassSyntaxReceiver());
}
public void Execute(GeneratorExecutionContext context)
{
if (context.SyntaxReceiver == null)
{
return;
}
PartialClassSyntaxReceiver syntaxReceiver = (PartialClassSyntaxReceiver)context.SyntaxReceiver;
if (syntaxReceiver != null &amp;&amp; syntaxReceiver.Results != null &amp;&amp; syntaxReceiver.Results.Any())
{
foreach (SyntaxReceiverResult result in syntaxReceiver.Results)
{
// based on the qualification process
// we know the qualifying node will be a class
ClassDeclarationSyntax cls = result.Node.AsClass();
context.GenerateSource($&quot;{cls.GetNamespace()}_file&quot;, fileBuilder =&gt;
{
fileBuilder.WithNamespace($&quot;{cls.GetNamespace()}&quot;, nsBuilder =&gt;
{
nsBuilder.WithClass($&quot;{cls.GetName()}_generated&quot;, clsBuilder =&gt;
{
clsBuilder.AsPublic();
clsBuilder.WithMethod(&quot;Hello&quot;, &quot;void&quot;, mthBuilder =&gt;
{
mthBuilder.AsPublic()
.WithBody(&#64;&quot;Console.WriteLine($&quot;&quot;Generator says: Hello&quot;&quot;);&quot;);
});
});
});
});
}
}
}
}
</code></pre>
<ul>
<li>The <code>Initialize</code> method is used to register the custom <code>ISyntaxReceiver</code> implementation containing the qualification rules - this is part of the normal Roslyn source generation processes (not specific to the <code>Source Generator Toolkit</code>)</li>
<li>The <code>GeneratorExecutionContext</code> parameter passed to the <code>Execute</code> method contains a <em>ISyntaxReceiver</em> implementation property - <code>PartialClassSyntaxReceiver</code> in this example, which contains the <em>Results</em> property with the qualifying SyntaxNode(s). A number of checks are performed to ensure the <em>SyntaxReceiver</em> is not null, and that the <em>Results</em> property on it is not null.</li>
<li>The code then iterates over each <code>SyntaxReceiverResult</code> in the <em>Results</em> property. In other words, <em>iterating through each qualifying node</em></li>
<li>The <code>AsClass</code> extension method (part of the <code>Source Generator Toolkit</code>) will convert the generic SyntaxNode to the specific syntax type ('ClassDeclarationSyntax' in this example)</li>
<li>The <code>GenerateSource</code> extension method (again, part of the <code>Source Generator Toolkit</code>) then allows for the building up of the required source code as described above. However, now, instead of explicitly supplying the values for the code (the <em>file name</em>, <em>namespace</em> and <em>class name</em> in this example), the provided extension methods are used to extract the values from the qualifying syntax node.</li>
<li>In this example, the <code>GetNamespace</code> and <code>GetName</code> extension methods on <code>ClassDeclarationSyntax</code> are used to get the relevent details from the syntax to populate the generated source code</li>
</ul>
<hr />
<h2 id="custom-syntax-qualifiers">Custom syntax qualifiers</h2>
<p>The <code>Source Generator Toolkit</code> allows for custom qualification checks using the <code>WithQualifyingCheck</code> method:</p>
<pre><code class="language-csharp">syntaxNode.NodeQualifiesWhen(Results, node =&gt;
{
node.WithQualifyingCheck(customNode =&gt;
{
// completely un-useful check
return customNode.ChildNodes().Count() == 10;
});
});
</code></pre>
<p>Here instead of checking if the node is a <em>class or attribute</em> for example, the qualification check is to see if the node contains 10 child nodes (a not very useful check)</p>
<h2 id="future-enhancements">Future enhancements</h2>
<p>The library is a work in progress, with common source generator functionality added initially, but with more to come over time. Some future enhancements include (but not limited to):</p>
<ul class="contains-task-list">
<li class="task-list-item"><input disabled="disabled" type="checkbox" /> SyntaxNode <code>AsAttribute</code> extension method</li>
<li class="task-list-item"><input disabled="disabled" type="checkbox" /> Additional extension methods to be used on <em>ClassDeclarationSyntax</em> and <em>AttributeDeclarationSyntax</em> to be leverage when doing code generation in a source generator</li>
<li class="task-list-item"><input disabled="disabled" type="checkbox" /> Ability to determine qualification with generics and generic types</li>
<li class="task-list-item"><input disabled="disabled" type="checkbox" /> Ability to determine qualification based on a code comment</li>
</ul>
<p>Feel free to log a request or bug if you have a specific requirement and I'll try to implement asap.</p>
<hr />
<h2 id="useful-links">Useful links</h2>
<p><a href="https://www.nuget.org/packages/SourceGeneratorToolkit">Source Generator Toolkit</a><br />
<a href="https://github.com/JoanComasFdz/dotnet-how-to-debug-source-generator-vs2022">Debugging a source generator</a></p>
</content:encoded>
<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
</item>
<item>
<title>Sharing a common method across classes</title>
<link>https://alwaysdeveloping.net/p/2023-05-interface-extension</link>
<description>always learning | always growing</description>
<guid>https://alwaysdeveloping.net/p/2023-05-interface-extension</guid>
<pubDate>Fri, 26 May 2023 03:00:00 GMT</pubDate>
<content:encoded><h2 id="introduction">Introduction</h2>
<p>Have you needed to add the same method to multiple classes? To have a single method in the code applied to multiple classes, instead of duplicating the code in multiple places?</p>
<p>This article will detail a technique (which I have personally been using extensively) which <code>allows for a single extension method to easily be added to any class</code>.</p>
<hr />
<h2 id="inheritance">Inheritance</h2>
<p>Before getting to the extension method technique, we are going to have a quick look at using inherence to solve the problem. A common method in a base class can be used to add the functionality to child classes:</p>
<pre><code class="language-csharp">// BaseClass which has common functionality
public class BaseClass
{
public BaseClass ExecuteBaseFunctionality()
{
Console.WriteLine(&quot;Executing Common functionality&quot;);
return this;
}
}
// Class1 which can execute Class1 specific functionality
// as well as the common functionality
public class Class1 : BaseClass
{
public Class1 ExecuteClass1Functionality()
{
Console.WriteLine(&quot;Executing Class1 functionality&quot;);
return this;
}
}
// Class2 which can execute Class2 specific functionality
// as well as the common functionality
public class Class2 : BaseClass
{
public Class2 ExecuteClass2Functionality()
{
Console.WriteLine(&quot;Executing Class2 functionality&quot;);
return this;
}
}
</code></pre>
<p>The reason for returning the <strong>class type</strong> from the methods, is to allow for <strong>method chaining</strong> to take place:</p>
<pre><code class="language-csharp">Class1 c1 = new Class1();
c1.ExecuteClass1Functionality()
.ExecuteBaseFunctionality();
</code></pre>
<p>However, if the common functionality (a call to the base class method) is required to be executed first, then a cast is required:</p>
<pre><code class="language-csharp">Class1 c1 = new Class1();
((Class1)c1.ExecuteBaseFunctionality())
.ExecuteBaseFunctionality();
</code></pre>
<p>Not ideal, but also not a big issue.</p>
<p>One big limitation of the inheritance approach is that if the class (<code>Class1</code> or <code>Class2</code> in this example) already inherits from another class, then the inheritance method simple will not work as C# does not allow for multiple inheritance:</p>
<pre><code class="language-csharp">// Already inherits, cannot inherit from &quot;BaseClass&quot;
public class Class1 : AnotherBaseClass
{
public Class1 ExecuteClass1Functionality()
{
Console.WriteLine(&quot;Executing Class1 functionality&quot;);
return this;
}
}
</code></pre>
<p><code>Interfaces combined with extension methods</code> to the rescue!</p>
<hr />
<h2 id="interfaces-extension-methods">Interfaces + Extension Methods</h2>
<p>This technique may seem a bit complicated initially, and once the foundations have been setup it is incredibly easy and quick to add the common method to any class.</p>
<h3 id="defining-the-interface">Defining the interface</h3>
<p>The first step is to define a <code>marker interface</code> which will be used as the base for the extension method:</p>
<pre><code class="language-csharp">public interface IHasCommonFunctionality&lt;TParent&gt;
where TParent : class
{
}
</code></pre>
<p>The interface uses a <em>generic parameter</em> to indicate the parent type - this is so the specific type can be returned from the extension methods to <em>enable method chaining</em> (shown further down in the post). If method chaining is not required, the generic parameter can be removed:</p>
<pre><code class="language-csharp">public interface IHasCommonFunctionality
{
}
</code></pre>
<hr />
<h3 id="defining-the-extension-method">Defining the extension method</h3>
<p>The next step, is to define an extension method, which <code>extends the functionality of the interface</code>:</p>
<pre><code class="language-csharp">public static class BaseFunctionalityExtensions
{
// Extension method on IHasCommonFunctionality with a specific generic type parameter
public static TParent ExecuteBaseFunctionality&lt;TParent&gt;(this IHasCommonFunctionality&lt;TParent&gt; parent)
where TParent : class
{
Console.WriteLine(&quot;Executing Common functionality&quot;);
// returns the parent, cast to the actual parent type
return (TParent)parent;
}
}
</code></pre>
<p>At first glace, there is a lot going on - but broken down:</p>
<ul>
<li>This is an extension method on the <code>IHasCommonFunctionality&lt;&gt;</code> interface. Any class which implements this interface, will have the <code>ExecuteBaseFunctionality</code> method available</li>
<li>The method uses the generic parameter <code>TParent</code> - this is the same parameter used when implementing the interface on a class, <code>IHasCommonFunctionality&lt;TParent&gt;</code></li>
<li>The method returns the generic parameter type (allowing for <em>method chaining</em>). As the returned <em>parent</em> variable is of type <code>IHasCommonFunctionality&lt;TParent&gt;</code>, and we want to return <code>TParent</code>, <em>parent</em> is cast to <code>TParent</code>.</li>
<li>The above cast will <em>always be valid</em> as the type represented by <code>TParent</code>, will always implement <code>IHasCommonFunctionality&lt;TParent&gt;</code></li>
</ul>
<p>A practical example might make it easier to see how the pieces fit together.</p>
<hr />
<h3 id="interface-implementation">Interface implementation</h3>
<p>The interface can now me implemented on one or many classes:</p>
<pre><code class="language-csharp">public class Class1 : IHasCommonFunctionality&lt;Class1&gt;
{
public Class1 ExecuteClass1Functionality()
{
Console.WriteLine(&quot;Executing Class1 functionality&quot;);
return this;
}
}
public class Class2 : IHasCommonFunctionality&lt;Class2&gt;
{
public Class2 ExecuteClass2Functionality()
{
Console.WriteLine(&quot;Executing Class2 functionality&quot;);
return this;
}
}
</code></pre>
<p>As you can see, the generic parameter for <code>IHasCommonFunctionality&lt;&gt;</code> is the <em>class the interface is being implemented on</em>. This gives the extension method visibility of the type that is leveraging the interface.</p>
<p>The extension method can now be leveraged from multiple classes::</p>
<pre><code class="language-csharp">Class1 c1 = new Class1();
// ExecuteBaseFunctionality called on Class1, and the
// Class1 instance is returned allowing
// ExecuteClass1Functionality to be called
c1.ExecuteBaseFunctionality()
.ExecuteClass1Functionality();
//-----------
Class2 c2 = new Class2();
// ExecuteBaseFunctionality called on Class2, and the
// Class2 instance is returned allowing
// ExecuteClass2Functionality to be called
c2.ExecuteBaseFunctionality()
.ExecuteClass2Functionality();
</code></pre>
<p>In the two example above, calling <code>ExecuteBaseFunctionality</code> on an instance of <code>Class1</code> returns the <em>Class1 instance</em> will calling the method on <code>Class2</code> returns the <em>Class2 instance</em>, allowing method chaining to still be possible.</p>
<hr />
<h2 id="conclusion">Conclusion</h2>
<p>When it's not possible to use inheritance to share a common method across multiple classes, the <code>interface + extension method</code> technique can prove to be very valuable. Once the ground work has been done, introducing the method to a class is as simple as having the class implement the required interface. In addition, as multiple interface implementations are allowed its possible add different extension methods to different classes independently (not possible with the inheritance technique)</p>
<p>I'm interested to know if this same problem has been solved in any other ways - please comment below with any additional techniques to leverage to solve the problem.</p>
</content:encoded>
<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
</item>
<item>
<title>Daily Drop wrap-up</title>
<link>https://alwaysdeveloping.net/dailydrop/2023/02/01-daily-drop-wrap</link>
<description>always learning | always growing</description>
<guid>https://alwaysdeveloping.net/dailydrop/2023/02/01-daily-drop-wrap</guid>
<pubDate>Wed, 01 Feb 2023 01:00:00 GMT</pubDate>
<content:encoded><h2 id="daily-knowledge-drop">Daily Knowledge Drop</h2>
<p>At the start of 2022 I set myself the goal of <code>learning one new coding related piece of knowledge a day</code>. It could be anything - some.NET / C# functionality I wasn't aware of, a design practice, a cool new coding technique, or just something I find interesting. It could be something I knew at one point but had forgotten, or something completely new, which I may or may never actually use.</p>
<p>The Daily Drop was <code>started in February 2022</code> as a record of these pieces of knowledge - writing about and summarizing them helped re-enforce the information for myself, as well as potentially helps others learn something new as well.</p>
<p>One year, and 246 Daily Drops later (only week days, and 2 weeks off during December) the Daily Drop goal <code>is completed!</code>. This post serves as a <em>wrap-up, as well as to highlight lessons learnt during the year</em>.</p>
<h2 id="observations">Observations</h2>
<h3 id="forgotten-knowledge">Forgotten knowledge</h3>
<p><code>Use the knowledge learnt - or forget it</code>. There are obviously exceptions to this, but for most developers unless we actively use a technique, method, syntax often, it needs to be looked-up each time. I am no exception to this. A number of the pieces of knowledge learnt throughout the year, was knowledge I had previous learn (sometime in the past 20 years), but was not actively using, and had thus &quot;forgotten&quot;. Reading about it again as part of the Daily Drop exercise just refreshed them memory and reminded me that I had actually previous learnt it.</p>
<hr />
<h3 id="source-of-knowledge">Source of knowledge</h3>
<p>Finding good sources of knowledge, which offer a mix between new C# features, and leveraging existing features is tough (but doable), but key. Two of my favorite sources (which are updated in the morning and afternoon CAT respectively) are <a href="https://blog.cwa.me.uk/">The Morning Brew</a> and the <a href="https://www.alvinashcraft.com/">The Morning Dew</a>. Both of these are aggregators for various Developer news.</p>
<p>Other sources include, but not limited to:</p>
<ul>
<li>Twitter .NET Community</li>
<li>Youtube: <a href="https://www.youtube.com/&#64;nickchapsas">Nick Chapsas</a>, <a href="https://www.youtube.com/&#64;RawCoding">Raw Coding</a>, <a href="https://www.youtube.com/&#64;CodingTutorialsAreGo">Coding Tutorials</a></li>
<li>Github repos</li>
</ul>
<hr />
<h3 id="technical-writing-is-a-skill">Technical writing is a skill</h3>
<p>Technical writing is a skill and takes times. Writing working coding samples is relatively quick - translating that into readable, understandable but concise and interesting posts is tough, and is time consuming. I feel most of the time I got this mostly right, but not always. However, as with most skills, practice over time improved my ability to write technical specifications, and this has carried over into my professional job.</p>
<hr />
<h2 id="going-forward">Going forward</h2>
<p>Do I feel like I gained skills and knowledge from Daily Drop? Yes!
Did I, overall, enjoy doing the Daily Drop? Yes!
Am I glad the year log goal has come to an end? Yes!</p>
<p>Writing a blog post daily is time consuming and at times was very draining. So, while the daily posts will stop, they will be replaced by less frequent but more comprehensive posts. The additional time not blogging, will be dedicated to new side projects and implementation of new ideas.</p>
</content:encoded>
<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
</item>
<item>
<title>EF queries on unmapped types</title>
<link>https://alwaysdeveloping.net/dailydrop/2023/01/31-ef-unmapped-types</link>
<description>always learning | always growing</description>
<guid>https://alwaysdeveloping.net/dailydrop/2023/01/31-ef-unmapped-types</guid>
<pubDate>Tue, 31 Jan 2023 01:00:00 GMT</pubDate>
<content:encoded><h2 id="daily-knowledge-drop">Daily Knowledge Drop</h2>
<p>Entity Framework 8 is (<em>potentially</em>) introducing new functionality allowing <code>raw queries to be executed on unmapped types</code>.</p>
<p>At the time of this post, the functionality is only available on the <a href="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet8/nuget/v3/index.json">daily builds</a>, and may change before the EF8 release.</p>
<hr />
<h2 id="sqlquery-example">SqlQuery Example</h2>
<p>Making use of the new functionality is fairly straight-forward. To use the new functionality, we need a <code>type</code>:</p>
<pre><code class="language-csharp">public class Blog
{
public int Id { get; set; }
[MaxLength(500)]
public string Title { get; set; }
public DateTime DateCreated { get; set; }
}
</code></pre>
<p>A <code>DbContext</code> is also required:</p>
<pre><code class="language-csharp">public class DemoContext : DbContext
{
public DemoContext() : base()
{
}
public DemoContext(DbContextOptions&lt;DemoContext&gt; options) : base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(
&#64;&quot;Server=.\SQLEXPRESS;Database=Demo;Integrated Security=True;TrustServerCertificate=True&quot;);
}
}
</code></pre>
<p>The important thing to note here, is that the <code>Blog type is NOT mapped to a DBSet in the DBContext</code></p>
<p>With the new functionality, <em>raw SQL queries</em> can now be executed against the <code>unmapped type</code> (<em>Blog</em> in this example):</p>
<pre><code class="language-csharp">using var context = new DemoContext();
// Blog type is not mapped
var blogs = await context.Database.SqlQuery&lt;Blog&gt;(
&#64;$&quot;SELECT b.Id, b.Title, b.DateCreated
FROM Blog b&quot;)
.ToListAsync();
Console.WriteLine($&quot;Blogs returned: {blogs.Count}&quot;);
</code></pre>
<p>The same functionality can be leveraged for <em>simple types</em>:</p>
<pre><code class="language-csharp">using var context = new DemoContext();
var titles = await context.Database.SqlQuery&lt;string&gt;(
&#64;$&quot;SELECT b.Title
FROM Blog b&quot;)
.ToListAsync();
</code></pre>
<p>This functionality can also be abstracted to a generic method to make calling it multiple times, for multiple entities easier:</p>
<pre><code class="language-csharp">async Task&lt;List&lt;T&gt;&gt; ExecuteSqlQuery&lt;T&gt;(DbContext context, string query)
{
return await context.Database.SqlQuery&lt;T&gt;(
FormattableStringFactory.Create(query)
).ToListAsync();
}
</code></pre>
<p>This method can now be called as follows:</p>
<pre><code class="language-csharp">var results = await ExecuteSqlQuery&lt;Blog&gt;(context,
&quot;SELECT b.Id, b.Title, b.DateCreated FROM Blog b&quot;);
</code></pre>
<hr />
<h2 id="dynamiccontext">DynamicContext</h2>
<p>I have previous written a <a href="https://www.nuget.org/packages/AlwaysDeveloping.EntityFrameworkCore.DynamicContext">NuGet package called DynamicContext</a> which effectively provides the same functionality. A detailed <a href="https://www.alwaysdeveloping.net/p/11-2020-dynamic-context/">blog post is also available</a>.</p>
<p>So will this new EF functionality replace <code>DynamicContext</code>? Yes, and no.</p>
<p>For the most part, yes it does replace <code>DynamicContext</code>. However there is one bit of functionality available in <code>DynamicContext</code> that is not available with the new functionality - the <code>ability to run queries against anonymous types</code>. This is possible with <code>DynamicContext</code>:</p>
<pre><code class="language-csharp">// Declare an example anonymous object with
// the relevant properties, using default values
var anon = new { BlogId = 0, Url = &quot;&quot; };
// Invoke the method just using the
// example object, and not specifying T
var blog = CallWithAnon(anon);
static T CallWithAnon&lt;T&gt;(T example) where T: class
{
// T is inferred from the example parameter (which is not used in the method,
// it is only used for the inference) and can successfully
// call into the dynamic runtime context
using var dynContext = new RuntimeContext&lt;T&gt;();
return dynContext.Set&lt;T&gt;().FromSqlRaw(&quot;SELECT Id as BlogId, Url FROM Blog&quot;)
.AsNoTracking().First();
}
</code></pre>
<p>Trying the same technique with the new EF functionality results in the following error:</p>
<pre><code class="language-terminal">No suitable constructor was found for entity type '&lt;&gt;f__AnonymousType0&lt;int, string&gt;'.
he following constructors had parameters that could not be bound to properties of the entity type:
Cannot bind 'BlogId', 'Title' in '&lt;&gt;f__AnonymousType0&lt;int, string&gt;(int BlogId, string Title)'
</code></pre>
<p>This is a fairly niche use case though, so for the majority of the time, the <code>new functionally can replace DynamicContext</code>.</p>
<hr />
<h2 id="notes">Notes</h2>
<p>If the ability to query unmapped entities is required - this new functionality is the way to go (vs custom libraries). I'm happy to see additional <em>required</em> functionality such as this being introduced into the base EF libraries, removing the reliance on additional libraries.</p>
<hr />
<h2 id="references">References</h2>
<p><a href="https://steven-giesel.com/blogPost/d1f069fb-7f6d-4f80-a98f-734755474ae1">Entity Framework 8: Raw SQL queries on unmapped types</a><br />
<a href="https://twitter.com/ajcvickers/status/1616203415637618688">Arthur Vickers Tweet</a></p>
<?# DailyDrop ?>246: 31-01-2023<?#/ DailyDrop ?>
</content:encoded>
<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
</item>
<item>
<title>ArrayPool for frequent array creation</title>
<link>https://alwaysdeveloping.net/dailydrop/2023/01/30-araypool</link>
<description>always learning | always growing</description>
<guid>https://alwaysdeveloping.net/dailydrop/2023/01/30-araypool</guid>
<pubDate>Mon, 30 Jan 2023 01:00:00 GMT</pubDate>
<content:encoded><h2 id="daily-knowledge-drop">Daily Knowledge Drop</h2>
<p>In situations where <em>arrays are created and destroyed frequently</em>, using the <code>ArrayPool&lt;T&gt;</code> class to <em>rent and return</em> memory buffers, instead of initializing an array, can lead to improved performance and less pressure on the garbage collection process.</p>
<hr />
<h2 id="array-initialization">Array initialization</h2>
<p>The <em>usual traditional</em> way to instantiate an array, is to use the <code>new</code> keyword:</p>
<pre><code class="language-csharp">void UseInitArray(int arrayLength)
{
ArrayItem[] array = new ArrayItem[arrayLength];
for (int i = 0; i &lt; arrayLength; i++)
{
array[i] = new ArrayItem
{
Id = i,
Name = i.ToString()
};
}
}
</code></pre>
<p>Here an array of <em>arrayLength</em> is initialized with <code>ArrayItem[] array = new ArrayItem[arrayLength];</code>. An <em>ArrayItem</em> instance is then added to each element of the array.</p>
<p>When a large number of arrays and created and destroyed frequently, the garbage collector is (comparatively) under pressure, as there are large amounts of memory allocated to the various large arrays which need to be cleaned up.</p>
<p>This is where the <code>ArrayPool&lt;T&gt;</code> class plays its part.</p>
<hr />
<h2 id="arraypool">ArrayPool</h2>
<p><code>ArrayPool&lt;T&gt;</code> shines because it allows already allocated space to be <code>rented</code>, before it is returned back to the pool. This eliminates the need for new memory to be allocated, and then cleaned up by the garbage collector:</p>
<pre><code class="language-csharp">void UseArrayPool(int arrayLength)
{
ArrayItem[] array = ArrayPool&lt;ArrayItem&gt;.Shared.Rent(arrayLength);
try
{
for (int i = 0; i &lt; arrayLength; i++)
{
array[i] = new ArrayItem
{
Id = i,
Name = i.ToString()
};
}
}
finally
{
ArrayPool&lt;ArrayItem&gt;.Shared.Return(array);
}
// DO NOT DO THIS
// array[0] = null;
}
</code></pre>
<p>Instead of the <code>new</code> keyword being used to instantiate the array, a block of memory (of the appropriate size for the array we required) is <code>rented</code> from the <em>ArrayPool</em>, using <code>ArrayItem[] array = ArrayPool&lt;ArrayItem&gt;.Shared.Rent(arrayLength);</code></p>
<p>Once the array (and the memory allocated to it) is no longer required, the memory is <code>returned</code> to the <em>ArrayPool</em>, allowing it to be reused in future.</p>
<p>It is important to <code>not access the array</code> once the memory has been returned to the pool, as this could cause instability in the application.</p>
<hr />
<h2 id="notes">Notes</h2>
<p>If an application creates and destroys a large number of array's, then using the <code>ArrayPool</code> is the way to go. It is not significantly more complicated that manually instantiating the array, and the application could gain an improvement in performance by leveraging the <code>ArrayPool</code>.</p>
<hr />
<h2 id="references">References</h2>
<p><a href="https://twitter.com/StasYakhnenko/status/1618293902670454786">Stas Yakhnenko Tweet</a></p>
<?# DailyDrop ?>245: 30-01-2023<?#/ DailyDrop ?>
</content:encoded>
<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
</item>
<item>
<title>Expression-body constructor</title>
<link>https://alwaysdeveloping.net/dailydrop/2023/01/27-expression-body-constructor</link>
<description>always learning | always growing</description>
<guid>https://alwaysdeveloping.net/dailydrop/2023/01/27-expression-body-constructor</guid>
<pubDate>Fri, 27 Jan 2023 01:00:00 GMT</pubDate>
<content:encoded><h2 id="daily-knowledge-drop">Daily Knowledge Drop</h2>
<p>An <code>expression</code> can be used as the body of a constructor, providing a more concise (but arguably, more complex) style.</p>
<hr />
<h2 id="traditional-constructor">Traditional constructor</h2>
<p>Traditionally, the constructor for an entity would have a parameter for each property of the entity and set the property value to the parameter value (or to a default):</p>
<pre><code class="language-csharp">public class Song
{
public string Artist { get; set; }
public string Name { get; set; }
public int LengthInSeconds { get; set; }
// set all property values based on parameters
public Song(string artist, string name, int lengthInSeconds)
{
Artist = artist;
Name = name;
LengthInSeconds = lengthInSeconds;
}
// set property values based on parameters and
// default values
public Song(string artist, string name)
{
Artist = artist;
Name = name;
LengthInSeconds = 0;
}
}
</code></pre>
<p>While there is absolutely <em>nothing wrong with this approach</em>, it is a fair number of lines of code just to set a few properties. A more concise approach, would be to use an <code>expression</code> for the body of the constructor.</p>
<p>--</p>
<h2 id="expression-bodied-constructor">Expression-bodied constructor</h2>
<p>The constructors can be rewritten as follows, using expressions for the body of the constructor:</p>
<pre><code class="language-csharp">public class Song
{
public string Artist { get; set; }
public string Name { get; set; }
public int LengthInSeconds { get; set; }
// set all property values based on parameters
public Song(string artist, string name, int lengthInSeconds) =&gt;
(Artist, Name, LengthInSeconds) = (artist, name, lengthInSeconds);
// set property values based on parameters and
// default values
public Song(string artist, string name) =&gt;
(Artist, Name, LengthInSeconds) = (artist, name, 0);
}
</code></pre>
<p>Here, a powerful feature of <code>Tuples</code> is leveraged. A <em>Tuple</em> created from the values passed into the constructor (or default values), is assigned to a <em>Tuple</em> created using the properties of the class. This will essentially <code>assign the parameter values to the property values</code>.</p>
<p>Definitely a more concise approach, although if unfamiliar with the syntax and how <em>Tuples</em> work, can definitely be a more confusing approach.</p>
<hr />
<h2 id="notes">Notes</h2>
<p>If concise, lean and clean code is the goal, then <code>expression-body constructors</code> is the way to go. As mentioned, the syntax can be more confusing when compared with the traditional approach - especially to those unfamiliar with <em>Tuples</em> and their properties.</p>
<hr />
<h2 id="references">References</h2>
<p><a href="https://twitter.com/mjovanovictech/status/1617071212504440832">Milan Jovanović Tweet</a></p>
<?# DailyDrop ?>244: 27-01-2023<?#/ DailyDrop ?>
</content:encoded>
<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
</item>
<item>
<title>Calling an async method in a constructor</title>
<link>https://alwaysdeveloping.net/dailydrop/2023/01/26-async-constructor</link>
<description>always learning | always growing</description>
<guid>https://alwaysdeveloping.net/dailydrop/2023/01/26-async-constructor</guid>
<pubDate>Thu, 26 Jan 2023 01:00:00 GMT</pubDate>
<content:encoded><h2 id="daily-knowledge-drop">Daily Knowledge Drop</h2>
<p>As it is <em>not possible to await an async method in a constructor</em>, if an async method <em>has</em> to be called, a valid technique is to <code>call the async method in the constructor, but defer the await until later</code>.</p>
<hr />
<h2 id="non-async">Non async</h2>
<p>Calling a <code>non async</code> method in a constructor is straight forward:</p>
<pre><code class="language-csharp">public class MyClass
{
private readonly string _specialData;
public MyClass()
{
// takes long, not ideal
_specialData = ExternalService.GetData();
}
}
</code></pre>
<p>Here, an external service is called to get data required for <code>MyClass</code> to function correctly.</p>
<p>However, is the scenario when <code>ExternalService.GetData()</code> is an async method <code>ExternalService.GetDataAsync()</code> handled?</p>
<hr />
<h2 id="async">Async</h2>
<h3 id="getresult">GetResult</h3>
<p>If the only option to get the require data is via a <em>async method</em>, simply just calling it in the constructor will not work:</p>
<pre><code class="language-csharp">public class MyClass
{
private readonly string _specialData;
public MyClass()
{
// Won't work!
// Return type is Task&lt;string&gt; not string
// _specialData = ExternalService.GetDataAsync();
// Won't work!
// To use await, the method needs to be async
// but constructors cannot be async
//_specialData = await ExternalService.GetDataAsync();
}
}
</code></pre>
<p>One <code>not recommended</code> option is to do the following:</p>
<pre><code class="language-csharp">public class MyClass
{
private readonly string _specialDataTask;
public MyClass()
{
_specialData = ExternalService.GetDataAsync().GetAwaiter().GetResult();
}
}
</code></pre>
<p><code>.GetAwaiter().GetResult()</code> is used on the <em>Task</em> returned from <em>GetDataAsync</em> - generally not a good idea to use this approach.</p>
<hr />
<h3 id="lazy">Lazy</h3>
<p>A better option is to use the <code>lazy initialization approach</code>:</p>
<pre><code class="language-csharp">public class MyClass
{
private readonly Task&lt;string&gt; _specialDataTask;
public MyClass()
{
_specialDataTask = ExternalService.GetDataAsync();
}
public async Task DoWorkUsingSpecialDataAsync()
{
var _specialData = await _specialDataTask.ConfigureAwait(false);
// Do the work using _specialData
}
}
</code></pre>
<ul>
<li>The type of the &quot;_specialData&quot; variable was changed from <code>string to Task&lt;string&gt;</code></li>
<li>In the constructor, the <code>async method is called, but not awaited</code> - this returns a <em>Task&lt;string&gt;</em></li>
<li>When/if the &quot;_specialData&quot; value is required, then the <em>Task&lt;string&gt;</em> is awaited to get the actual value</li>
</ul>
<p>With this method, when the constructor is called, the process of getting the special data is initiated, but is not blocking. When it comes time to use the value returned from the process, <code>await</code> is used to get the value from the <em>Task</em>. Either the processing is finished and the value will be available immediately, or the process is still ongoing and the value will be returned once the process is completed.</p>
<hr />
<h2 id="notes">Notes</h2>
<p>Ideally, this scenario should probably be avoided all together - but if it is a requirement, the lazy-initialization technique is great way to solve the problem.</p>
<hr />
<h2 id="references">References</h2>
<p><a href="https://endjin.com/blog/2023/01/dotnet-csharp-lazy-async-initialization">Lazy and once-only C# async initialization</a></p>
<?# DailyDrop ?>243: 26-01-2023<?#/ DailyDrop ?>
</content:encoded>
<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
</item>
<item>
<title>Case-less Dictionary keys</title>
<link>https://alwaysdeveloping.net/dailydrop/2023/01/25-dictionary-comparer</link>
<description>always learning | always growing</description>
<guid>https://alwaysdeveloping.net/dailydrop/2023/01/25-dictionary-comparer</guid>
<pubDate>Wed, 25 Jan 2023 01:00:00 GMT</pubDate>
<content:encoded><h2 id="daily-knowledge-drop">Daily Knowledge Drop</h2>
<p>The <code>Dictionary</code> constructor can take a <code>StringComparer</code> parameter allowing for retrieving of keys from the dictionary while ignoring the case of the key. This removes the need to perform <em>ToUpper</em> and <em>ToLower</em> on the calls involving the key.</p>
<hr />
<h2 id="without-stringcomparer">Without StringComparer</h2>
<p>Without a <code>StringComparer</code>, the case of the <em>key added to the dictionary, and the case of the key when performing a lookup, need to match</em>:</p>
<pre><code class="language-csharp">Dictionary&lt;string, int&gt;? artistAlbum = new Dictionary&lt;string, int&gt;();
// Call made to .ToLower() to ensure all artist
// names are in the same standard format
artistAlbum.Add(&quot;Foo Fighters&quot;.ToLower(), 10);
artistAlbum.Add(&quot;John Mayer&quot;.ToLower(), 8);
// check will only return true if using lower case values,
// or specifically calling ToLower
Console.WriteLine(artistAlbum.ContainsKey(&quot;Foo Fighters&quot;)); // false
Console.WriteLine(artistAlbum.ContainsKey(&quot;Foo Fighters&quot;.ToLower())); // true
Console.WriteLine(artistAlbum.ContainsKey(&quot;foo fighters&quot;)); // true
</code></pre>
<p>In this example, <code>ToLower</code> is called each time an item is added to the Dictionary. When performing a check to see if the Dictionary contains a key, a match will only be found if the supplied value is all lower case, or if <code>ToLower</code> is specifically called again. This ensure that the keys are always stored, and then looked-up in a consistent format - lower case in this example.</p>
<p>However, all the <code>ToLower</code> (or <code>ToUpper</code>) calls do have a performance impact, and additionally they have to manually be added everywhere the Dictionary is used. A simpler and better approach is to use a <code>StringComparer</code>.</p>
<hr />
<h2 id="with-stringcomparer">With StringComparer</h2>
<p>Using the <code>StringComparer</code> technique is as simple as passing a value into the <code>Dictionary</code> constructor:</p>
<pre><code class="language-csharp">Dictionary&lt;string, int&gt;? artistAlbum =
new Dictionary&lt;string, int&gt;(StringComparer.OrdinalIgnoreCase);
artistAlbum.Add(&quot;Foo Fighters&quot;, 10);
artistAlbum.Add(&quot;John Mayer&quot;, 8);
Console.WriteLine(artistAlbum.ContainsKey(&quot;Foo Fighters&quot;)); // true
Console.WriteLine(artistAlbum.ContainsKey(&quot;Foo fighters&quot;)); // true
Console.WriteLine(artistAlbum.ContainsKey(&quot;foo fighters&quot;)); // true
</code></pre>
<p>With <code>StringComparer.OrdinalIgnoreCase</code> is supplied to constructor, <code>ToLower</code> is no longer required when adding or checking the existence of a key. The case is now ignored when doing the comparison - this results in cleaner code, and better overall performance.</p>
<hr />
<h2 id="notes">Notes</h2>
<p>If the <code>Dictionary</code> could contain keys of various cases (maybe based on user input) then <code>StringComparer</code> should be used over <em>ToLower</em> or <em>ToUpper</em>. There is no overhead to using this approach, and is actually cleaner and more performant.</p>
<hr />
<h2 id="references">References</h2>
<p><a href="https://linkdotnet.github.io/tips-and-tricks/dictionary/#pass-in-stringcomparer-to-dictionary">Pass in StringComparer to Dictionary</a></p>
<?# DailyDrop ?>242: 25-01-2023<?#/ DailyDrop ?>
</content:encoded>
<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
</item>
<item>
<title>LINQ lambda vs method group</title>
<link>https://alwaysdeveloping.net/dailydrop/2023/01/24-lambda-vs-method</link>
<description>always learning | always growing</description>
<guid>https://alwaysdeveloping.net/dailydrop/2023/01/24-lambda-vs-method</guid>
<pubDate>Tue, 24 Jan 2023 01:00:00 GMT</pubDate>
<content:encoded><h2 id="daily-knowledge-drop">Daily Knowledge Drop</h2>
<p>When using an <em>expression</em> with LINQ, <code>a lambda should be preferred over a method group</code> as the performance is slightly better. Lambda expressions can be cached by the runtime resulting in the increased performance.</p>
<hr />
<h2 id="examples">Examples</h2>
<p>In the below example we'll be filtering a collection of integers, to return only the values which are <em>greater than 100</em>.</p>
<p>The <em>Where</em> method on <code>IEnumerable&lt;int&gt;</code> accepts a <code>Func&lt;int, bool&gt;</code> - this can be defined as an actual method, or as a lambda method. We'll have a look at each technique, and then compare performance.</p>
<hr />
<h3 id="method-group">Method group</h3>
<p>With a collection of integers, to filter using the <em>Where</em> method with a <code>method group</code>, a method need to be defined which <em>accepts an int and returns a bool</em>:</p>
<pre><code class="language-csharp">// simple method which accepts an int
// and returns true if the value is
// greater than 100
static bool GreaterThan100(int value)
{
return value &gt; 100;
}
</code></pre>
<p>This method can then be used in a <em>Where</em> method call:</p>
<pre><code class="language-csharp">// collection of 100 integers
IEnumerable&lt;int&gt;? items = Enumerable.Range(50, 150);
// filter using a method group
IEnumerable&lt;int&gt;? filteredItems = items.Where(GreaterThan100);
</code></pre>
<hr />
<h3 id="lambda">Lambda</h3>
<p>With the <code>lambda technique</code> the separate defined method is invoked manually with the parameter specified:</p>
<pre><code class="language-csharp">IEnumerable&lt;int&gt;? items = Enumerable.Range(50, 150);
// &quot;manually&quot; call the method, sending the int value
// &quot;manually&quot; to the method
var filteredItems1 = items.Where(i =&gt; GreaterThan100(i));
</code></pre>
<p>Both techniques will yield the same results, and on the surface look (and are) very similar. However, next let's look at the performance of each technique to see the main difference.</p>
<hr />
<h2 id="performance">Performance</h2>
<p>For the performance benchmarking, the following <em>lambda</em> and <em>method group</em> were tested:</p>
<pre><code class="language-csharp">public class Benchmarks
{
private IEnumerable&lt;int&gt; items = Enumerable.Range(1, 10000);
[Benchmark(Baseline = true)]
public List&lt;int&gt; MethodGroup() =&gt; items.Where(IsDivisibleBy5).ToList();
[Benchmark]
public List&lt;int&gt; Lambda() =&gt; items.Where(i =&gt; IsDivisibleBy5(i)).ToList();
private static bool IsDivisibleBy5(int i) =&gt; i % 5 == 0;
}
</code></pre>
<ul>
<li>a collection of <em>10000 integers</em> was used</li>
<li>each item was checked to determine if it was <em>division by 5 or not</em></li>
</ul>
<p>The results:</p>
<table>
<thead>
<tr>
<th>Method</th>
<th style="text-align: right;">Mean</th>
<th style="text-align: right;">Error</th>
<th style="text-align: right;">StdDev</th>
<th style="text-align: right;">Ratio</th>
<th style="text-align: right;">RatioSD</th>
</tr>
</thead>
<tbody>
<tr>
<td>MethodGroup</td>
<td style="text-align: right;">75.04 us</td>
<td style="text-align: right;">1.483 us</td>
<td style="text-align: right;">2.079 us</td>
<td style="text-align: right;">1.00</td>
<td style="text-align: right;">0.00</td>
</tr>
<tr>
<td>Lambda</td>
<td style="text-align: right;">66.44 us</td>
<td style="text-align: right;">1.306 us</td>
<td style="text-align: right;">2.146 us</td>
<td style="text-align: right;">0.89</td>
<td style="text-align: right;">0.04</td>
</tr>
</tbody>
</table>
<p>From the results, we can see that the <code>lambda technique is approx. 10% faster than the method group technique</code>.</p>
<hr />
<h2 id="notes">Notes</h2>
<p>The difference between the two methods is this example (10%) may seem fairly significant, but the timescale is in <em>nanoseconds</em> - a 10% difference at this scale will not be noticeable. However, depending on the collection size and the complexity of the calculation, the difference could be more noticeable.<br />
In short - for most scenarios using either technique will be fine, however if performance is an issue, or there is a specific bottleneck, then consider explicitly using the lambda technique.</p>
<hr />
<h2 id="references">References</h2>
<p><a href="https://linkdotnet.github.io/tips-and-tricks/advanced/lambda_methodgroup/">Lambda vs method group</a></p>
<?# DailyDrop ?>241: 24-01-2023<?#/ DailyDrop ?>
</content:encoded>
<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
</item>
<item>
<title>Task.Delay accuracy</title>
<link>https://alwaysdeveloping.net/dailydrop/2023/01/23-task-delay</link>
<description>always learning | always growing</description>
<guid>https://alwaysdeveloping.net/dailydrop/2023/01/23-task-delay</guid>
<pubDate>Mon, 23 Jan 2023 01:00:00 GMT</pubDate>
<content:encoded><h2 id="daily-knowledge-drop">Daily Knowledge Drop</h2>
<p><code>Task.Delay</code> relies on the underlying operating system's internal timer, which for most Windows environments, takes about 15ms to resolve. This means that the <em>minimum amount of time that can be accurately used with Task.Delay is approximately 15ms (on Windows)</em></p>
<hr />
<h2 id="sample">Sample</h2>
<p><code>System.Diagnostics.StopWatch</code> can be used to benchmark how long a <code>Task.Delay</code> call actually takes:</p>
<pre><code class="language-csharp">Stopwatch? watch = Stopwatch.StartNew();
await Task.Delay(100);
watch.Stop();