How to bend reality to your will with C# Source Generators

แชร์
ฝัง
  • เผยแพร่เมื่อ 11 เม.ย. 2021
  • Become a Patreon and get source code access: / nickchapsas
    Check out my courses: dometrain.com
    Hello everybody I'm Nick and in this video I will show you how you can use C# 9's Source Generators feature to write code that writes code. The posibilities are limitless, from mappers, to source generated dependency injection. In this video I will show you just a couple of examples and scratch the surface of the feature's potential.
    Don't forget to comment, like and subscribe :)
    Social Media:
    Follow me on GitHub: bit.ly/ChapsasGitHub
    Follow me on Twitter: bit.ly/ChapsasTwitter
    Connect on LinkedIn: bit.ly/ChapsasLinkedIn
    Keep coding merch: keepcoding.shop
    #dotnet #csharp #sourcegenerators

ความคิดเห็น • 59

  • @capsey_
    @capsey_ 3 ปีที่แล้ว +55

    Everyone gangsta till your program rewrite itself to go against Three Laws of Robotics

  • @MarcusOrciuch
    @MarcusOrciuch 3 ปีที่แล้ว +50

    Damn Nick you fly through Rider like you made it. Can you make a video about all the different productivity tips in Rider?

  • @thibaudgallanddemanneville174
    @thibaudgallanddemanneville174 3 ปีที่แล้ว +6

    awesome! Exactly what I was looking for to automatically generate my classes =) I will give it a try soon!

  • @dcuccia
    @dcuccia 3 ปีที่แล้ว

    Exactly what I was looking/hoping for to get me started, thanks!!

  • @walterh2113
    @walterh2113 3 ปีที่แล้ว

    Very useful video, I hadn't get around yet to messing with source generation!

  • @promant6458
    @promant6458 3 ปีที่แล้ว +9

    Actually, attributes in source generators SHOULD NOT be identified using ToString(). It is 100% possible, that a user marks a member with attribute using a qualified name (e.g. [System.Serializable]) or an alias. In both these cases, the generator wouldn't execute, because it looks for a specific string. That's why it is better to use SemanticModel of the current SyntaxTree and an INamedTypeSymbol of the attribute we are looking for. Thanks to that the generator will always properly identify the AttributeSyntax and will never fail due to the style of the users code.

    • @nickchapsas
      @nickchapsas  3 ปีที่แล้ว +1

      None of this is supposed to be a "How to use source generators properly" and it is mentioned in the video as well. This is just about showcasing the possibilities. You would normally use the syntax classes and the factories to create nodes in the tree.

    • @promant6458
      @promant6458 3 ปีที่แล้ว +2

      Also, source generators can be easily debugged without all this Debugger.Launch stuff. All that is really needed is an unit test, an instance of GeneratorDriver and an instance of Compilation.

    • @promant6458
      @promant6458 3 ปีที่แล้ว +1

      @@nickchapsas Yes, I am aware of that. This is just a little disclaimer that building a useful generator is not as straight-forward as it seems.
      Anyway, thanks for the video. Finally a subject I can actually 100% relate to.

    • @nickchapsas
      @nickchapsas  3 ปีที่แล้ว +1

      Oh no they are actually really hard to work with an understand. I've been using the graph syntax to build the new classes in my own time and I am ashamed to admit how much time it took me to understand some of the very basic stuff. Debugging wise, I knew about the unit test approach but that feels like a hack as well. It would be good if they add some sort of "proper" way of doing it, even though I don't know what that would look like exactly.

    • @promant6458
      @promant6458 3 ปีที่แล้ว +1

      @@nickchapsas Yes, whole Roslyn API is really hard to work with, especially source generators. The worst part is the complete lack of documentation. I wasted literal weeks finding out how to show errors as red lines in the editor, just to find a single mention on Roslyn's github that source generators can't do that. They can report errors, they can specify location of the error, but they can't show them. What the heck?!
      It turned out that the only way to achieve that is to write a seperate analyzer that does the error handling. So, the same validation code has to be executed TWICE, once with diagnostics, once without.
      Writing generators is just as painful as satisfying.

  • @toastybowl
    @toastybowl 3 ปีที่แล้ว +2

    Excellent--now it seems more than a dream to create some analyzer which can do more than chastise myself & my teammates.
    Now we can reduce the file count necessary to implement features. My employer will be furious!

  • @tobiasraphaeldieckmann426
    @tobiasraphaeldieckmann426 3 ปีที่แล้ว

    Couldn't you have make more use of the attributes by getting the "instance" and getting the property values or is this not possible during compile time, because there is no instance and you need to iterate through the parameters?

  • @fifty6737
    @fifty6737 ปีที่แล้ว +1

    5 years down the line when the analyzers packages become dev friendly, we gonna see some impressive stuff, compile time di, compile time cqrs basically you name it, the .net landscape will be so different

  • @InshuMussu
    @InshuMussu 2 ปีที่แล้ว

    Great work as you always do

  • @paulecampbell
    @paulecampbell 3 ปีที่แล้ว

    great stuff Nick

  • @weluvmusicz
    @weluvmusicz 3 ปีที่แล้ว +1

    The "attach to debuggger window" does not appear when i rebuild the whole solution. Anyone an idea?

  • @pawetarsaa9904
    @pawetarsaa9904 2 ปีที่แล้ว +1

    I wonder how to make the tests of generated code

  • @tapstach2872
    @tapstach2872 3 ปีที่แล้ว

    My generator runs the first time it's built or referenced or debugged, and not again. Might it be a visual studio fault

  • @paulmouatib9999
    @paulmouatib9999 3 ปีที่แล้ว +1

    Great course as always!
    I have a question though, could you make a video about the best way to handle time and time localisation (for storage AND user display). I've seen it done in several ways and I don't really know what is adviced by Microsft on the subject. Do you have some experience with this kind of issue?
    Imagine a central server communicating with several sensors around the world. Some times you want to display the measurement in UTC, some times in the local sensor date time... What is the best way to do that?

    • @nickchapsas
      @nickchapsas  3 ปีที่แล้ว

      Depending on your usecase, DateTimeOffset or UTC only DateTime should be able to be flexible enough to deal with time and time localisation matters

    • @pilotboba
      @pilotboba 3 ปีที่แล้ว +1

      While the .Net date types can get you there, they are awkward. Take a look at NodaTime.

  • @neighbourhater
    @neighbourhater 2 ปีที่แล้ว

    This is great, is the code available online?

  • @Time21
    @Time21 3 ปีที่แล้ว +2

    Hello Nick, can you do a debugging video?

  • @alexvanheerden5702
    @alexvanheerden5702 3 ปีที่แล้ว +2

    For your mappable generator, why are you filtering on a string? ie. AttributeLists.Any(xx => xx.ToString().StrartsWith("Mappable") )...
    Can you not do type checking like AttributeLists.Any(xx => xx is MappableAttribute)... or something ?

    • @nickchapsas
      @nickchapsas  3 ปีที่แล้ว +4

      You can and that’s how you would properly do it but it’s not as simple are you described. The syntax is more complicated. Doing it on string is very unsafe. This video demonstrates the feature not the best practices

  • @willinton06
    @willinton06 3 ปีที่แล้ว +5

    .NET is so damn hot right now

  • @evanboltsis
    @evanboltsis 3 ปีที่แล้ว

    Νίκο καλησπέρα, εξαιρετική δουλειά με τα βίντεο! Ήθελα να σε ρωτήσω, το IDE της JetBrains σε έχει βοηθήσει παραπάνω από το visual studio; Ευχαριστώ.

    • @nickchapsas
      @nickchapsas  3 ปีที่แล้ว +2

      Ναι είναι το βασικό μου IDE εδώ και 3 χρόνια και μπορώ με σιγουριά να πω ότι είναι κλάσεις ανώτερο από το VS. Έχω ήδη ένα βίντεο πάνω στο θέμα.

  • @TheOceanLoader
    @TheOceanLoader 3 หลายเดือนก่อน

    I didn't understand until I had watched a few times that your controller was automatically generated from your class!

  • @szymonb5834
    @szymonb5834 3 ปีที่แล้ว +1

    Hi Nick! Have you tried to add a third-party library to your generator (i.e. Newtonsoft.Json)? I did and I found it very difficult to make it work (at least in VS). There are some tricks (i.e. assembly resolving on runtime, registering in GAC), but it works in very indeterministic way (at least in VS - FileNotFound exceptions). However I haven't tried Source Generators in Rider. Maybe Rider is more mature than VS is right now.

    • @nickchapsas
      @nickchapsas  3 ปีที่แล้ว +1

      Yes I am using jab and I had no problems in Rider

    • @szyb
      @szyb 3 ปีที่แล้ว

      @@nickchapsas Thanks! Then I'll try Rider instead

  • @ovidiufelixb
    @ovidiufelixb 3 ปีที่แล้ว +5

    I don't understand: How come developing and using source generators is so much worse in VS than in Rider? A couple of weeks ago I tried messing around with creating my own source generator in VS but the experience was awful: after each change to the generator project, the IDE had to be restarted to register the changes, and in the end I didn't even get Intellisense suggestions for my generated namespace, which kind of rendered the whole thing useless.
    Anyway, thanks for another awesome video!

    • @tobiasraphaeldieckmann426
      @tobiasraphaeldieckmann426 3 ปีที่แล้ว

      From my opinion, it's not a question about VS or Rider. As Microsoft is working on it right now, a couple of weeks are the span of time, where it was improved ;-) I think it's no longer necessary to reload the whole solution by restarting VS (I came to this point as well a few month ago ;-))

  • @gavinlangley8411
    @gavinlangley8411 3 ปีที่แล้ว +1

    The obvious question is what can you do with this that you could not do with generics? Perhaps efficiency or to put that another way making generics more like C++ templates. If something cannot be generics/templated then yeah but then this code becomes the template - but in code instead. The controller is a good example but that's more a limitation of the controllers. If you continue with the mapping you need other meta data about the mapping. Whichever way you do it you need other meta data to drive the code gen. One technique I use is model meta with interfaces that point to lambdas. Then you define the lambda for each model. I have been consider using refection for the default behaviour but I'm reluctant to do that. This may be a a good alternative to get the default lamdas. I'm sure there must be some other cool dynamic behaviours possible but I'm struggling to see a real life one though.

    • @nickchapsas
      @nickchapsas  3 ปีที่แล้ว

      This has nothing to do with generics and everything to do with reflection. It's about removing the performance bottleneck or reflection and replacing it with compile time generated code. You can get a 7x performance improvement just by using Source Generated Dependency injection as opposed to the built in reflection based one. Same goes with the application wiring code and way more.

    • @gavinlangley8411
      @gavinlangley8411 3 ปีที่แล้ว +1

      @@nickchapsas Yes sure you could auto generate a non-generic code but the you can simply write that code once anyway. It you want to auto generate code many times, and that is where the power of this is, then it is exactly like generics but in code. The question is just which . Then you should see the similarity between this and C++ templates which are code generated rather than run-time executions. I think you are missing my point. Great video though it really sparked my curiosity.

  • @JakeAndDaddy
    @JakeAndDaddy 3 ปีที่แล้ว

    The trick is to get the attributes injected by your source generator.
    Debugger.Launch worked on its own for me.

  • @PatrickMageez
    @PatrickMageez 2 ปีที่แล้ว

    Source generators feel like an amazing solution for certain problems. But may be the worst solution to solving others. I guess the tricky thing about this new feature is knowing when to use them and when to go with something else? Where's the line between knowing source generators will be the right approach or doing something with dynamic or another language might be a better option? These are just my thoughts. Anyone who has anything more on this concern of mine please reply. Would be interested to know of some solid use cases for it and some other use cases where source generators might look like a good fit but really in the long term they are probably bad. Lastly, awesome video thanks for showing this feature!

    • @MD-vs9ff
      @MD-vs9ff ปีที่แล้ว +1

      Source generation is for boiler plate. The boring crap where you have to do the same stuff all the time, like implementing an INotifyPropertyChanged interface in WPF and raising the property changed notification on each property. Instead you can just slap [ObservableObject] tag on the class and [ObservableProperty] on each of the properties and it's all done under the hood. Oh, another property depends on that value to and needs to raise a change notification? You have [NotifyPropertyChangedFor()] for that.

  • @danielsun0402
    @danielsun0402 7 หลายเดือนก่อน

    Hi Nick, it seems that they improve and change a lot of things in the last 2 years. Especially with .Net 8 your example does not work for me (I'm probably to stupid).
    Can you make a updated Video about this topic?

  • @f135ta
    @f135ta ปีที่แล้ว

    Isnt this just Roslyn (from years and years ago) renamed and re-released as a new feature?

  • @clearlyunwell
    @clearlyunwell 3 ปีที่แล้ว

    👍

  • @destroyonload3444
    @destroyonload3444 3 ปีที่แล้ว +1

    Within the first two minutes I said..."WHAT THE F@!# !?????" hahaha okay, I'll watch the rest now to see if there's a catch.

  • @fededevi1985
    @fededevi1985 3 ปีที่แล้ว +2

    YO DAWG

  •  3 ปีที่แล้ว

    It is really a bit hacky and ugly, but seems feasible to generate unit tests against entities. I know, I know... I'm from those who see value unit tests against entity classes. Hopefully, MS going to add better templating.

  • @igorsentrxigorsentrx5550
    @igorsentrxigorsentrx5550 3 ปีที่แล้ว

    as for me, that is your best video.

  • @user-tk2jy8xr8b
    @user-tk2jy8xr8b 2 ปีที่แล้ว

    > this is kinda way worse
    exactly. Why not adding syntactic macros already? Like it was done in Nemerle

  • @fr3ddyfr3sh
    @fr3ddyfr3sh ปีที่แล้ว

    Geez, MS refuses to introduce macros since the birth of C# and reinvents more or less working solutions (T4, Sourcegen, IL weaving).
    We could have solved this stuff for years with macros. 😑
    It’s so painful to work with source gens which solve only halve of the problems, and are still not well supported in the latest VS 2022.
    Heck they didn’t even port their test helpers from source-gen to incremental-source-gen, so that you are forced to write your own, when you migrate 😤

  • @mdabuzar2130
    @mdabuzar2130 3 ปีที่แล้ว

    Really, you are from the same planet?

    • @igorthelight
      @igorthelight 3 ปีที่แล้ว

      Welcome to the overcomplicated coding ;-)

  • @L4rsTrysToMakeTut
    @L4rsTrysToMakeTut 3 ปีที่แล้ว +1

    Are you up for the real thing. Writing code with code. We could set up an video call and I'll show you julia lang

    • @nickchapsas
      @nickchapsas  3 ปีที่แล้ว +1

      Fun fact, Julia is one of my favourite "side" languages

    • @L4rsTrysToMakeTut
      @L4rsTrysToMakeTut 3 ปีที่แล้ว +1

      @@nickchapsas Are you up for a little julia jam?

  • @NoGamer256
    @NoGamer256 3 ปีที่แล้ว

    I bend reality to my will with Harmony lib o man the nasty things you can do.

  • @noctavel
    @noctavel 2 ปีที่แล้ว

    I sincerely think Microsoft is going towards the wrong direction with this generator stuff. Rust macros are so much simpler and powerful.
    Wish microsoft did something similar.

  • @JonathanPeel
    @JonathanPeel 2 ปีที่แล้ว

    You left out //This was created by a tool