Boosting Productivity with .NET Source Generators
0 views
Jun 19, 2025
This session will explore how source generators can revolutionize your development workflow. We'll start by defining source generators and contrasting them with traditional runtime code generation techniques. We'll then dive into the core concepts, dissecting the anatomy of a source generator and demonstrating how they interact with the compiler pipeline. You'll learn how to leverage syntax trees and semantic models to analyze your existing code and generate new code based on it. Conference Website: https://dotnetconference.com 📺 CSharp TV - Dev Streaming Destination http://csharp.tv 🌎 C# Corner - Community of Software and Data Developers https://www.c-sharpcorner.com #CSharpTV #CSharpCorner #LiveShow #dotNet #DotNetConf2025
View Video Transcript
0:00
i would like to say hello to uh to all the audiences around the globe watching us Uh today I'm going to talk about net
0:07
source generators a very fascinating feature introduced in net 5 and today
0:13
we're going to explore it uh in the depths and see how we can utilize this
0:18
in our applications Before diving into the source codes and writing some fancy
0:24
source codes let's see uh what's source generators uh according to Microsoft
0:30
source generators uh aim to enable compile time meta programming that's
0:35
code that can be create a compile time and this is the compilation source generators uh will be able to read read
0:42
the uh contents of the compilation before running crucial
0:49
here because in previous versions we had the reflections that we can uh view the
0:56
the source codes or write dynamic coal reflections but it has its own advantage and disadvantage or performance
1:02
penalities in source generators we will able to read the contents of the compilation before running it's very I
1:09
think uh great as well as access the additional files enabling generators to introspects the both user C code and
1:17
generate specific files really interesting generates create pipeline starting from a base input source and
1:25
mapping them to the output they wish to produce and the more exposed property
1:32
states that the earlier the compiler will be able to cut off chains and reuse the same output Uh as a sum up uh or
1:41
simply put source generation are library projects that you can add to solution or
1:47
include an existing noug packages They're meant to utilize only during the build process and add new code to a
1:53
project Uh it's very important to uh note this things that what are
2:01
source generators not meant to do It's very important Uh source generators are
2:06
not designed to replace new language features Uh we're not going to uh define
2:12
or create new language features and attach them to the for example the C# language uh because the C# language is
2:20
evolving it in its own pipeline and using the source generators to add
2:26
functionalities to the C# language will create dialects and it will be increase
2:31
our technical depth also uh using source generators we're not going to have the
2:38
uh things like code rewriting code writing are operations like optimization
2:44
logging injection I don't know waving call side rewriting These are very important things that we can do Uh but
2:51
source generators are not there to uh to help us in these situations Uh of course
2:59
while the techniques have many value use cases they do not fit into the idea of source generators They are by definition
3:05
called altering operations We're not going to alter the code We're going to generate our own source codes Also the
3:11
source generators uh are not analyzers A source generator
3:18
uh of course while often used together with analyzers uh and source generators
3:23
they have many in common but we use source generators against to generate new source codes and we use analyzers to
3:29
analyze the source code and generate the warnings and errors during our applications These are very important to
3:37
know that what are not source generators uh in a new newer version of net
3:43
Microsoft introduced the incremental source generators and it deprecated its
3:49
old source generator which we use the I source generator interface to implement source generator it's not deprecated and
3:56
incremental source generator are replaced with the uh I source generator
4:01
interface uh the reason behind this deprecation is
4:07
a bit clear uh because the source that perform is eval valuation execution on items only after they have some
4:13
filtering requirements significant increasing performance This is what we didn't have in the isource generators
4:19
that uh caused the heavy performance penalty using is source generators Of
4:24
course the interface exists you can use it implement the isource generator interface but it's not uh good option it
4:32
it would be best option to use the incremental source generator interface
4:38
to implement your own uh source generators This very uh quick and short
4:43
introduction to source generators and without any other uh points let's dive into the source code and see how we can
4:50
develop the source generators and how they can help us and how they can uh
4:56
speed up our developments Okay let's go to the visual and let me close this Oh
5:02
too many window here Uh in order to simulate the source generators I've created two uh projects here One web API
5:11
project and the other one is a class library project Let's start from the class library project In order to uh
5:20
implement a source generator your class library should use .NET standard
5:26
2.0 Why because the .NET compiler currently is supporting .NET standard
5:33
2.0 It means that you cannot create source generators using .NET 9 using
5:38
.NET 8 There are not valid options You should use D standard 2.0 Here my class
5:44
library is uh let's zoom it Yeah here my class library is using D
5:51
standard 2.0 uh and of of course there are some other options here that we're going to
5:59
uh I'm going to describe what are these beside the having the R2.0 the source
6:06
project needs to uh reference the Microsoft code analysis analyzer and
6:12
code analysis C# noug packages too uh which helps us to implement the source
6:19
generator in place Uh the other project is our web API projects We are open to
6:26
use any the framework we like Net 9 net 8 or whatever other versions of we are
6:32
okay to use Uh which one uh we want Okay As you see this very simple up to here
6:38
Let's get back to the s project of the generator project and see what are these
6:43
options here One of the very important option here is the uh enforce extended
6:48
analyzer rules uh this ensures the generators using the
6:54
recommended rules created by the data team The another option let's uh put an
7:00
inter here Okay The another option is the iso is a rosling component This
7:05
ensures that the projects to act as a uh generator and work with the rosling
7:10
compiler making debugging of the generator possible The other one is include build output equal to false This
7:18
prevents the project build from being included in output which is ideal since using the generators is means to be
7:25
compile time only In our traditional class library we used to set the include
7:30
build outputs to true because uh we intended to use the output of the class library or the DL files in our projects
7:38
But for source generators we're not going to use the output of the generators we're going to uh use the uh
7:46
source generator artifact as compile time So we should set the include build time output equal to the false Uh in web
7:55
API projects we have a reference to the source generator project It's uh like
8:01
before like any other uh project references that we had except two
8:06
important options Here we have defined that the reference output assembly is
8:11
equal to false and output item is equal to analyzer So up to here in the web API
8:18
CS project uh we have uh some question marks one is here what's reference
8:24
output assembly the other one is here what's output item type and the other ones are the ones that I have commented
8:31
I commented them what are the emit compiler generated files or what's the compiler generated files output pass
8:38
these are the options that we hadn't in our uh normal web API projects these are
8:44
some things that we added because of using the source generators as a reference in our
8:50
projects Uh sorry the emit compiler generated files
8:56
options enable us to save the generated source code in a file and the compiler
9:04
generated files output path defines the location where the file should be saved
9:09
In fact I'm going to tell the uh to tell my project says okay generate a file for
9:17
the generated sources and save that file in a generated files folder This uh this
9:25
location is relative to the uh sys projects
9:31
file So these are clear and they're very crucial for debugging the source for the
9:37
uh debugging the source generators Without these two options debugging the source generator would be a nightmare
9:43
It's one of the disadvantages of source generator Of course the the most important disadvantages of source
9:49
generators are the way we can debug them It's very uh hard to debug the items Uh
9:57
okay this is this is clear here And what is this reference output assembly and
10:02
output item type reference output assembly clearly says that I'm not going to reference any assembly file I'm not
10:09
going to reference any DL file here as mentioned in the uh my generator project
10:16
file is going to be a compile time artifact So I don't want to reference
10:22
the assembly in my web API project Instead I'm going to use this uh my
10:28
generator CS project as a helpers for my Rosen analyzer as I'm going to use it beside
10:35
my analyzer So the output I'm looking is that the my source generators should be
10:42
located in dependencies and analyzer sections Normally when I reference a
10:48
project it comes under projects section or under package sections But when I say
10:54
the output item type is equal to analyzer I'm going to view my uh
11:00
reference projects in the analyzers analyzers section So we have
11:06
uh some uh information about the CS projects and the structure of the CS projects and we know how to uh I mean
11:14
decorate the projects in order to start running this source generators
11:20
Uh let's get back to source code and see what's going on there Here in source code I have a class uh called it the
11:28
calculator class It has two properties A and B Uh what I'm going is I want to add
11:36
the mathematical operations to this class The four main mathematical operations add subtract multiply and
11:42
divide As you see in my calculator class I have not these methods and I'm going
11:49
to add these methods using source generator this class As I'm going to add new source codes to this class
11:54
definitions I need to define the class as a partial Of course it's optional I
12:00
can define the class as a non-partial class and add that four main mathematical operations as a helper
12:06
classes and then use them over the fly using the source generators That's that would be fine too But here in my
12:13
scenario I'm going to add that four operations exactly to the calculator class So I defined it as a partial class
12:19
and the other partial part of the class will be implemented using the source
12:25
generators Uh in order to define my own source generator in my source generator
12:31
project I have created a file called calculator generator calculator generator as you see is
12:38
implementing the II incremental generator interface which I told you that's a uh new
12:45
interface new interface uh I mean introduced in a new new version of the
12:51
net and of course every generators if wants to be act as a generator should be
12:58
decorated with a generator attribute so my class have two prerequis This one the
13:05
generator attribute I have added it to my source code Second one is to implement I increment generator
13:11
interface while implementing the I increment I incremental generator interface I need to give my own
13:19
implementations for the initialize method Uh in the first look this code
13:25
seems to be very sophisticated but in fact it's very simple We just needs to
13:32
uh to to be introduced to the new uh syntaxes of the rose lane and to the new
13:39
syntaxes of the source generators Uh before using the source generators
13:45
before working with source generators in in years we have used the
13:51
C# orn net we have got introduced to net classes and C# syntaxes We know that for
13:58
example public class something I can define a new class or I don't know
14:04
public void uh something I can define a method or I can define properties I I
14:10
know the syntax I must use in order to utilize the net or C# language here
14:17
while defining the source generators we are going to get introduced to the
14:22
something like Roslin syntaxes we're going to be introduced to something like
14:27
syntax provider syntax tree compilation unit uh things that are not are new for
14:34
us before working the source generator Uh we have I incremental gener
14:40
generator initialization context here Uh of course it provides it's it gives us
14:47
the initial methods to give access to underlying source code I'm using
14:52
instrumental generator initializing context I can get access to the underlying source code of the compilation unit Uh it gives me
15:00
different kinds of providers The four main providers that the incremental
15:06
generated initialization context gives me is syntax provider that that helps me to access to
15:13
the syntax tree to analyze transform and select nodes for future work The other
15:19
provider I can access which is important is uh compilation provider that can access data relevant to the entire
15:26
compilation such as assemblies source files and various solutionwide options
15:31
and configuration Uh and the other least important providers are uh parse option
15:38
providers gives access to various bits of input about the code being parsed or
15:44
the other pro the providers are uh additional text provider I think uh
15:50
metadata reference provider and other providers that's out of the scope of my speech today I'm going to focus on the
15:57
syntax pro provider so what was the syntax provider it access it helps me to
16:03
access the syntax tree So when I access the syntax tree I can analyze the syntax
16:08
tree I can transform the syntax tree as my intention and select nodes for feature work which is most commonly uh
16:16
accessed and used operation here Uh I have here context syntax
16:22
provider I'm going to access syntax provider and I'm going to create my own syntax provider uh using the create
16:29
syntax pro provider I needs to define two arguments One is predicate which is
16:36
super light uh predicate to filter out the extra information which I do not
16:42
want to work with them or to filter out the operation which I'm going to work with them In predicate for example I
16:48
mentioned that I'm going to looking for class declaration syntax Class declaration syntax means uh among all
16:56
the source code of the compilation unit I'm going to select only the uh text or
17:02
the declarations related to the class declaration something like public class X public class uh zip public class P I'm
17:11
going to just select these parts I'm not going to select the name space information I'm not going to select the
17:17
method information I'm going to focus only on the class declaration syntax and of Of course again I have added another
17:24
condition here Beside the selecting the class declaration I'm going to only
17:29
focus on a class declaration which its identifier or which its name is equal to
17:35
calculator So in my compilation unit uh I have a class like public partial class
17:42
calculator It's a class declaration Great And of course its identifier is
17:48
calculator So when the compiler comes to compile the source code this uh
17:53
perticate will filter out my class and gives me the and giving me the public
17:58
partial class of calculator I have now the public partial class calculator and
18:04
I can go through it modify it add operation to it I don't know add
18:09
comments to remove comments and do whatever I like After the predicate uh
18:15
uh filter outs the information it gives the output to the transform argument
18:21
transform argument of course here I'm going to say transform argument says okay just return the context node node
18:30
means the uh the class you have find this is a node this this line is a node
18:36
oh if I okay this is a node if my
18:41
transform method returns more than one value I can go through the different nodes and find my uh int intended nodes
18:49
but here the uh class declaration only returning one node I'm going to uh
18:55
directly cast the context node to the class declaration syntax because I know
19:00
that the return value of the predicate should be a class declaration
19:07
where I'm sure about this because in the predicate section I have filtered out only the class declaration to be
19:14
returned beside that their name should be calculator So in transform section I
19:20
get the uh ctx task nodes and now I have the
19:25
node and can I can go through the nodes to uh alter it and do whatever uh I'd
19:32
like to do uh of course we have very uh details here and we needs to focus on
19:38
what is syntax I don't know syntax node syntax tokens these are something I I
19:43
said that these are some things that might be new for the developers which are not gotten introduced to the Roslin
19:50
APIs or never worked with source generators but as introductions uh
19:55
things like uh public things like I don't know
20:01
partial things like abstract These are syntax tokens We call them we call them
20:08
syntax tokens And the syntax token tokens when comes uh together creates a
20:14
new definition creates a new definition This definition gives me a syntax node
20:19
This is the hierarchy we need to know in order to create a vual generator Okay
20:27
uh after selecting my uh node among the syntax node I'm going
20:33
to implement my own source code In order to implement source code I'm going to call the register source
20:40
output For a register source output I'm telling the register source output that I'm going to work with the output of the
20:47
calculate classes providers which we discussed it here And in order to uh
20:54
write our own custom source code in the second argument of register source output we're going to execute our
21:01
execute method This could be any name I have just put the execute name under and it could have uh numerous arguments But
21:09
in my own use case I needs to only pass the uh class declaration and the context
21:16
as my compilation unit Nerves change the compilation unit Okay let's see what's going on the execute method As you see
21:24
it's very straightforward Here we're going to uh check that if the method
21:31
with a name adds in a calculator class or not If the
21:38
calculator class already contains the method named add then of course I should
21:44
not add any other method with the same to the class because it might cause the compilation cause the compilation error
21:51
or it might cause the unintended behavior For example it might cause the
21:57
uh overridden of the methods implementation That would be uh not very nice options
22:03
here So in this section I'm going to tell the class member that okay inside
22:09
the class let's search for the method declaration syntax inside the class we have the
22:15
class have its own declaration syntax tree among that declaration syntax we
22:20
might have properties we might have fields we might have a variable constructors and methods I'm going to
22:26
only focus on methods okay filter out the methods here I'm going to say okay among the
22:32
methods let's see that are is there any method called add in this class or not
22:39
the same operation is going to be happen for the other three operations So is there any method called subtract
22:44
multiply divide in the class or not After uh this I'm going to uh find
22:52
the using in order to add the using section to my uh new class declarations
22:59
For that again I'm going to calculator class and parsing the syntax tree and
23:05
asking the syntax tree that hey syntax tree give me the using you have give me
23:10
the using because I need to put that using in my other partial class too I'm
23:16
taking over this using classes and append them to the my string builder
23:21
which acts as my final source code Uh the next part is to put my part This
23:28
operation is something uh optional I'm going to add my source codes of course based on my use cases I'm going to find
23:36
the name space of my partial class I mean I'm going to find out this
23:44
section that was the name space of this calculator class and I want to use this
23:51
name space as a name space of the other partial class uh and put these two partial class in the same name space In
23:58
order to do this again I'm going to ask the calculator class that's hey
24:03
calculator class let's uh go to your ancestors and list me all
24:09
namespace declaration syntaxes I mean that among all your ancestors your
24:14
direct ancestor or indirect ancestors uh give me the namespace declaration syntax
24:19
and tell me if there is any name space defined in the ancestors or not If there
24:25
are there is not any name space defined among ancestors uh it might be a sign
24:31
that there is not any name space declaration in that file Second option I
24:36
need to search for the phoscope name spaces in order to find out is there any
24:42
file scope name spaces which fit the calculator class or not Again I'm going
24:47
to search through the answers that is there any file scope name spaces available or not And I
24:55
uh I assume that the uh name spaces is exists in the name space declaration
25:02
syntax or at least as file scope name space declaration syntax If there is no name space in the namespace declaration
25:08
syntax and the file scope name space declaration syntax the CA namespace would be null and of course this line
25:14
would produce you the compile time errors So the here
25:19
you might of course do some other errors to handle the name space properly
25:25
Debugging the source generator as I told you it's a nightmare Logging is a nightmare It's not the same as the
25:32
logging we had in our traditional applications For example accessing the file or system.io in source generator is
25:39
totally blocked In order to use these output type options you might uh use the
25:45
shared library and make help of them in order to utilize the system.io in your
25:50
shared library and reference the uh shared library in your service generator and pass the uh intended logs to your
25:58
shared library and write them in file or or wherever uh you like to put it So the
26:04
error handling and the debugging of source trans would be very crucial here Okay
26:09
After finding out the name space I'm going to define my class My class would have mod uh my class would have
26:17
modifiers It would be public private internal whatever my class has I read
26:22
the modifier put the class keyword as a hardcoded here and read the identifier from the identifier After that I'm going
26:29
to add the add method implementation If it is not been it it has not been added
26:35
all the uh calculator class I'm going to add this method to my class and add the
26:41
other three operations to my uh class too Finally at this
26:47
point I have my uh source code I have my new source code as a string in this
26:54
section in the calc generated class building A very important po part part here is that while we're going to
27:01
analyzing the source generator analyzing the syntax tree everything uh from the
27:07
point of view from the syntax tree point of is a string accessing to class declaration is a string name space are
27:15
strings in syntax tree everything is a string so we can easily access the uh stringified version of our source code
27:22
using to string in every section of our code Of course when we want to access
27:28
the syntax tree we can use a dot to a string to stringify the syntax tree
27:33
content It's valid Of course in the vice versa section when we want to put the
27:39
new source code in the syntax tree we can impose the stringified version of the source code into the syntax tree
27:44
It's very uh it would very great option Of course in order to add the source
27:50
code to our compilation context we use the add source method For example I tell that I'm going to create a new file
27:57
called calculator I put G as a generator For example it's something related to
28:03
the convention that's yeah this file is generated in source generators You can put here whatever you want For example
28:11
it's not very important I'm going to create a new class called
28:16
calculator.g CS that's contents is equal to the calculator generated class
28:22
builder two strings If the source codes are included the UTF8 encoding
28:28
characters putting the encoding that UTF8 will be crucial of course here too For example language lots like Arabic or
28:36
like Forsy or Persian we have UTF8 encodings And if our source of if these
28:42
type of corctors are embedded in our source code we should use encoding the UTF8 Otherwise our source code will be
28:50
uh some question marks will be appeared inside our source code It's very important to point this options to Okay
28:58
Anyway with this uh introduction and overall look at source generators or we have defined our source generators let's
29:06
build the solution to see what's going on here Uh build
29:15
great and we're waiting to build operation to to complete Okay as you see
29:20
there's no warning here If there is any error inside your source generated code
29:28
that errors will be transformed as warning in your uh visual studio So you
29:33
should uh take a precise look for the warnings in Visual Studio 2 But here we do not have any warning It means that
29:39
there is not any error inside the source generator course too
29:45
uh as I stated here I state that I tell the source generator to emit this generated code to the generated files
29:53
folder Okay let's get to the generated files folder and see what's going on
29:59
there I have generated files folder here my generator and calculator Here is
30:05
calculator gs Let's open it and see what's going on inside Oh great That's the whole code we
30:13
have created here This our name space same as the calculator class name space
30:19
public parial class calculator again same as that and the methods I have
30:24
added here source generator second important
30:31
point here is attention if I again build a solution
30:38
Okay let's see here It tells that the generator calculator generator failed to
30:44
generate the source Why because inside the source generator you have mentioned
30:51
that the generated source should be saved into the calculator.g.cs file or technically
30:59
talking the source generator should be marked with this
31:04
calculator.g.cs hint The warning tells that hey man the
31:11
calculator g CS hint must be unique within the generator
31:17
You have used this calculator with the previous version of the source code Again you are going to tell me that yeah
31:23
put this in again for the new newly generated source code Uh that's true option that's very important The reason
31:31
for this error is originated from here as I told you uh enabling these options
31:38
uh is a good thing only for debugging the source generator After debugging is completed and I'm going to make in the
31:44
production I need to comment out these uh two options and prevent the source
31:50
generator from emitted to the uh file system Otherwise I I will have the
31:57
duplicate files with numerous names and with the inaccurate uh names Of course
32:03
that would that would not be a good options here Okay Oh we need
32:12
to Okay again build the projects here Okay
32:18
it build successfully Get back to the programs Okay I have to mess and I'm
32:24
going to sum up here Let's utilize the generated source code For example I'm
32:29
going to define a new get [Music]
32:36
method And here I'm going to create new objects of size
32:41
calculator in calculator that property A is equal to 20 and
32:47
calculator.property B is equal to uh 10 for example And then say the calculator
32:54
that uh do the add operation for me and and
33:00
return this as an output Okay Add requires two parameters
33:09
A and B
33:15
Oh calculator Finally calculator
33:21
Okay let's uh put F2 and see what's going As you see that it's stepped into
33:27
the source generator Here you can see the uh yellow ribbon here that says that
33:34
the current source code is generated by source generator and you're stepping into the code inside the source
33:40
generator Uh let's run the project to see the output Oh we have error
33:46
semicolon Okay
33:53
Okay the PI is up and running in local host 50 42 As you see we have
34:02
uh 30 here It means that the uh add operation
34:09
operated precisely I can replace it with the subtract method Let's hot reload it
34:18
Okay we have 10 here and the other parts as you see that
34:24
utilizing the source generator it seems to be very uh easy options but before
34:29
utilizing source generator we need to know what is a source generator what is not source generators and we need to get
34:36
introduced to the Roslin API syntax we need to get introduced to the C# compiler the data compiler syntax and
34:43
after getting introduced to this things working with source would very helpful
34:48
and of course it it will be uh solve many of the complex uh problems you
34:54
might have For example I have developed the source generator my own application
35:00
as a transformer between the model and the read only model CQR operations I
35:06
have model classes and I'm going to transfer the model class to read only models I can utilize the source
35:12
generators to convert these two types together In order to get access to the
35:17
source code of the sessions you can refer to my GitHub public
35:23
github.com/vironment generator sample and you can clone the code and starts
35:28
working