The New Way of Calling Your Code in .NET 8 Is INSANE

Поделиться
HTML-код
  • Опубликовано: 20 сен 2023
  • Use code DOCKER15 and get 15% off the brand new Docker course on Dometrain: dometrain.com/course/from-zer...
    Become a Patreon and get source code access: / nickchapsas
    Hello, everybody, I'm Nick, and in this video, I will introduce you to an extremely powerful feature added in .NET 8 called the UnsafeAccessor. This feature aims to replace reflection on many levels and provide compile time performance but also allow for NativeAOT support.
    Subscribe to Dan: @danclarkeuk
    Workshops: bit.ly/nickworkshops
    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
    #csharp #dotnet

Комментарии • 537

  • @gustavo-santos-dev
    @gustavo-santos-dev 8 месяцев назад +399

    This is probably a crime in +50 countries.

    • @dextergandini
      @dextergandini 8 месяцев назад +14

      It is also forbidden by Genebra convension!

    • @fakhrulhilal
      @fakhrulhilal 8 месяцев назад +3

      It means we can do anything what we want to be in any framework we’re using😂

    • @mattkins99
      @mattkins99 8 месяцев назад +8

      OMG I don’t want to support this when I find it 10 years from now in a class that starts with the comment // Don’t touch, thar be dragons

    • @adambelos2157
      @adambelos2157 8 месяцев назад +1

      Mama i am a criminal...

  • @clementdato6328
    @clementdato6328 8 месяцев назад +297

    Finally, I can change the value of a static private read only field of a class in some other person’s code so that when another person use my library they will learn to read through all code before actually believing something is read only and private.

    • @Spid88PL
      @Spid88PL 8 месяцев назад +20

      INSANE

    • @fifty-plus
      @fifty-plus 8 месяцев назад +22

      Make sure your comments are totally off base too 😉

    • @IvanRandomDude
      @IvanRandomDude 8 месяцев назад +17

      Truly a gAmE-cHaNgEr

    • @erynmacdonald
      @erynmacdonald 8 месяцев назад +5

      WARNING *sarcasm* DETECTED

    • @phizc
      @phizc 8 месяцев назад +11

      You could have done that in previous versions of .NET too. It's just become a more pleasant coding experience to do so now 😛.

  • @KieranFoot
    @KieranFoot 8 месяцев назад +178

    I'm guessing this is part of getting rid of reflection for AOT...

    • @peanutcelery
      @peanutcelery 8 месяцев назад +11

      Yeah a lot is being set up for AOT like minimal apis.
      I feel like .NET 8 was the setup to make AOT more common for the next .NET versions.

    • @z0nx
      @z0nx 8 месяцев назад +4

      Interesting.. Is it because this can be done at compile time or something?

    • @renauddanniau676
      @renauddanniau676 8 месяцев назад +3

      @@z0nx Exactly, I think they will combine this with source generator to generate code at compile time and not during runtime ;).

    • @RiversJ
      @RiversJ 8 месяцев назад +2

      Yup Native AOT plays a big role in .Net 8

    • @davidfowl
      @davidfowl 8 месяцев назад

      @@peanutcelerySomebody has been paying attention 🫡

  • @woocaschnowak
    @woocaschnowak 8 месяцев назад +32

    With great power comes great responsibility.
    Don't use your power to change static readonly fields :D

  • @ElmoTheAtheistPuppet
    @ElmoTheAtheistPuppet 8 месяцев назад +11

    "The value is Nick" - You are the value mate appreciate your work

  • @mrsajjad30
    @mrsajjad30 8 месяцев назад +10

    For this feature I must say "With greater power comes greater responsibility". Excellent demonstration. Thank you Nick.

  • @ristopaasivirta9770
    @ristopaasivirta9770 8 месяцев назад +17

    Who would win: ten years of SOLID principles vs one unsafe boi?

  • @DennisFazekas
    @DennisFazekas 8 месяцев назад +69

    This seems really handy for unit testing, but I have concerns about using it in other contexts. As someone who writes a lot of infrastructure code, I find it crucial to restrict developers from accessing certain parts of the code.

    • @Kerbiter
      @Kerbiter 8 месяцев назад +14

      Sure, except when stubborn library devs only design something in the way they see consumers want, not what the consumers really want, and won't change anything and/or it's a lot of hassle to make them change, or it's just simply the way they're building their library.

    • @parcanapp1193
      @parcanapp1193 8 месяцев назад

      nuke with mandatory .nuke folder immediately came to mind. I use .config for all configuration, and now have an extra folder. I will now go back and check if it is a static readonly as opposed to const by any chance. @@Kerbiter

    • @ehudv9276
      @ehudv9276 8 месяцев назад +2

      Yes. haven't thought of that. thats actually a good use case.

    • @DennisFazekas
      @DennisFazekas 8 месяцев назад +1

      ​@@KerbiterI totally get where you're coming from! If the devs aren't providing what's really needed, then there might be a bigger issue going on. I'm all about sharing knowledge and having open code reviews. That way, everyone knows what's going on in the code and if any tweaks are needed, I'm more than happy to make them. I'd rather work together like this than have people go around my code, which could create headaches down the road. 😊

    • @TheRavenCoder
      @TheRavenCoder 8 месяцев назад +1

      Unit tests are definitely the most obvious use case. I've used reflection before on unit tests and it's a bit messy. I didn't want to make the methods public, because they should not be used directly by the application, but the logic needed to be tested as mistakes could cost the company millions of dollars. This feature would've cleaned that code up a bit.

  • @PereViader
    @PereViader 8 месяцев назад +37

    Compile time performance is the best part of this ❤

    • @parlor3115
      @parlor3115 8 месяцев назад +2

      I don't think it matters since you're mostly going to use this in tests where you run your methods a few dozen times each at most.

    • @BillyBraga
      @BillyBraga 8 месяцев назад

      You can probably get the same perf with reflection if you compile lambda expressions

    • @neppe4047
      @neppe4047 8 месяцев назад

      ​@@BillyBragayeah I think he did something like that in another video, not sure why didn't in this one

  • @dhochee
    @dhochee 8 месяцев назад +12

    "It's a pain ... where you don't want to be painful" is hilarious. I'm gonna steal that. Regarding the main topic ... I've used reflection to access private members before, but only when it was an abstraction designed to handle cases where you don't know the member names at design-time. This new feature doesn't help with that, so it's just ignoring the original developer's intentions. I suppose if you absolutely need to do it, having it be declarative with "Unsafe" in the keyword is better than hiding it behind reflection. Also much faster, of course, as you observed.

  • @Demonata1223
    @Demonata1223 8 месяцев назад +7

    I had a very good use case for this recently. We use private constructors for some of our objects because we want to tightly control how new things are made. But that inadvertently effected serialization. System.Text.Json cannot serialize with private constructors. Newtonsoft can. Thats an example of when something is private. but you may still need to access it externally in some situations. I dont want to open up something thats private in the code base but i still want to be able to serialize/deserialize it properly.

  • @OlofLagerkvist
    @OlofLagerkvist 8 месяцев назад +17

    Great video, but I think one additional way of doing it should have been in the benchmark. That is, getting the MethodInfo object through reflection, then build a Func (or similar) delegate of it and then cache that delegate and call that instead of using the dynamic Invoke() method each time. Many years ago I changed that in lots of places in a code base that had a lot of reflection and improved performance a lot. The question now is how that compares to this new way of doing it!

    • @TheMonk72
      @TheMonk72 8 месяцев назад +4

      I routinely use LINQ lambda expressions to build funcs for methods I'm accessing via reflection because they're faster than invoking a MethodInfo. And they work well with generics. Would love to see a speed comparison with this.

  • @markhenderson5283
    @markhenderson5283 8 месяцев назад +15

    My experience with code using refection is it is either doing something really powerful and useful or something stupid. It is usually always the second one.

    • @anonimxwz
      @anonimxwz 8 месяцев назад +3

      Imo reflection is useful for testing private things or to call generic methods with multiples types.

  • @DivingDeveloper
    @DivingDeveloper 8 месяцев назад +1

    Thank you for this, Nick. Concise and helpful as always. I can see the use - as you demonstrated - clean and fast running, if potentially dangerous code.

  • @mindstyler
    @mindstyler 8 месяцев назад +50

    Will we get a dedicated in-depth video about the volatile keyword at some point? It's been 2 years already since you covered it briefly the last time.

    • @ludwintor4986
      @ludwintor4986 8 месяцев назад

      absolutely agree

    • @thatcreole9913
      @thatcreole9913 8 месяцев назад

      👀

    • @tarsala1995
      @tarsala1995 8 месяцев назад +3

      Ideally with some multithreaded examples

    • @IronJmo
      @IronJmo 8 месяцев назад

      It's funny seeing a comment about this because I just used this recently on a project for the first time.

    • @renauddanniau676
      @renauddanniau676 8 месяцев назад +3

      Volatile is not really complex, you should read what MSDN has on it and you will easily understand how to use it :).
      You need to have a good understanding about how multithreading works and what are L1, L2 and L3 caches.

  • @MichaelMortensen
    @MichaelMortensen 6 месяцев назад

    Wonderful insights, thanks!

  • @benjaminclehmann
    @benjaminclehmann 8 месяцев назад +18

    I'm wondering if this is safer, for example if the method doesn't exist or the signature is incompatible would this fail at compile-time? Because in that case this seems like a massive win, especially for those who are committing these types of sins on code they don't have access to.

    • @marton-vincze
      @marton-vincze 8 месяцев назад +2

      I highly doubt that compile time checking for private field are possible, the input parameter for the accessor can be typed as an interface or an abstract class where some implementations will possibly have this method/field

  • @BillyBraga
    @BillyBraga 8 месяцев назад +45

    Personally, I think a valid use case is when you are using a nuget package that doesn't expose the functionality or configuration required for functioning properly in your app.

    • @MayronDev
      @MayronDev 8 месяцев назад +6

      I've had this problem a number of times. One example has been when a package is serializing data using its own internal serializer and does not provide any configable settings or callbacks. This has prevented me from using custom logic required by an app I was working on. It's good to open up an issue on their pull request but that could delay your code from going live or completely block you if they choose to ignore your issue for years.

    • @phw1009
      @phw1009 8 месяцев назад +1

      That will be very useful, especially on nuget packages those not maintained anymore.

    • @noon9548
      @noon9548 8 месяцев назад +1

      ​@@phw1009how would you improve the packages that not maintained anymore? Do you mean changing inners of packages or extending functionality?

    • @davidmartensson273
      @davidmartensson273 8 месяцев назад

      @@noon9548 It could be enough to be able to access some internals to be able to work around a problem.

  • @99aabbccddeeff
    @99aabbccddeeff 8 месяцев назад

    It's really helpful feature in some rare cases. Thanks for the sharing.

  • @TheRicherthanyouguy
    @TheRicherthanyouguy 8 месяцев назад +33

    I’m so mixed on this I can definitely see value from a unit testing perspective because there are codebases that have private methods that really have too much going to be private. Which really just needed to be rewritten. I strongly dislike accessing things that should be private purposefully but I also love the performance boost

    • @leerothman2715
      @leerothman2715 6 месяцев назад +1

      I can see it being useful for testing DDD classes that have immutable properties on a test fixture setup. Not sure I’d use it for executing private methods though. Unit tests should be decoupled from the implementation of the subject under test.

    • @TheRicherthanyouguy
      @TheRicherthanyouguy 6 месяцев назад

      @@leerothman2715 agreed I think we are all mostly on the same page of this can be useful but only in rare or extreme situations.

  • @F1nalspace
    @F1nalspace 8 месяцев назад

    This is awesome! I had some cases in the past, where i had to use reflection to get a private value out - and it was very slow.
    Great that there is now a tool for doing the same thing - and more, for compile time performance. I like it ;-)
    Thanks for sharing.

  • @PeterOeC
    @PeterOeC 8 месяцев назад +1

    My mind was blown once, when my colleague showed me how to make a self-updating const in JavaScript.
    Now you're showing me that private properties can be changed from outside classes 🤯
    I need to sit down

  • @IceQub3
    @IceQub3 8 месяцев назад

    Thanks I will use it in all my code now

  • @DemoBytom
    @DemoBytom 7 месяцев назад +1

    This is gonna be used in source generators so much, and I'm 99% sure that was the main reason the feature got introduced to the runtime.
    In pre .NET 8, to extend a class with source generator you have to make the class partial, and then have the generator create the extension in the class' partial.
    With this feature we will be able to extend non partial classes, just as if they were, without bloating said class with the generated methods, you might NOT need outside of what the generated code was for. This is an amazing, though very dangerous, thing indeed.

  • @TohidAzizi
    @TohidAzizi 6 месяцев назад

    Nice! it is something that I probably only use in my unit tests!

  • @Tolg
    @Tolg 8 месяцев назад +7

    This is fantastic! I think it will allow for me to make more things private, and still have them testable. I’ve had so many cases where I couldn’t make something private because I needed to expose to my testing framework.

    • @filadog
      @filadog 8 месяцев назад

      @@jkdmyrs how do you test private async event handlers on UI, say WinForms? This will be handy in such cases when in memory UI testing is required. Faking button clicks and such. In my place we use MVP pattern for UI code extensively and have a custom framework for testing presenters with specflow. It's real nice to work with, you just say User clicks button "Download". And reflection magic calls private event handler for that button in the presenter. Might use this feature in the future instead.

    • @jangohemmes352
      @jangohemmes352 8 месяцев назад +1

      The tests are screaming at you that you aren't designing your code and tests right. NEVER test internals. They are internal so that they are free to change without breaking tests

    • @Tolg
      @Tolg 8 месяцев назад +1

      I know this is a contentious topic and I don't intend to start a, how to correctly write and test your code correctly war, here in Nick's video comments. In general, I do agree with you. You should only need to test your public interfaces. However, even for backend code, sometimes in libraries there is good reason unit test certain methods such as utility methods which may have flexibility extended to them to address future needs or test integration code that is not conducive to easily being mocked out without leaking abstraction. You could abstract out such code, mark things as internal and add InternalsVisibleTo to your library to allow its testability, but I feel that modifying a base library in such a way just to be able to test, is not exactly proper either. So I will certainly experiment with this new capability to help improve my code and my code's testability.

    • @paulcarlton598
      @paulcarlton598 7 месяцев назад +1

      I've dealt with this too, to get around it, I'll create a testing interface for the object only to expose the needed methods through that testing interface only. It's a way to keep the intent of the contract while being able to cast to a testing interface for the unit test suite. This functionality though actually gets rid of that need which I definitely appreciate, because in all honesty I feel like my workaround, although stays clean, is kind of a workaround.

  • @gliaMe
    @gliaMe 8 месяцев назад

    Regarding the code mess of the reflection solution, I had an extension method for the reflection calls in a project. Worked for any property of any class.

  • @innerbytes
    @innerbytes 8 месяцев назад

    I see it very usefull for testing in some scenarios.

  • @rreiter
    @rreiter 8 месяцев назад +1

    5:50 Yes, I want to easily access private members that I shouldn't be using, and, oh, 11:00 so much for readonly, ... this will be fun (especially if it is performant, lol). I wish the Law worked like this: "Yes, Officer, I broke this law, but I said a special word when I was doing the bad act, so that makes it ok and it's all good."

  • @anm3037
    @anm3037 8 месяцев назад +1

    The first place I will use it is to grab the array under List

    • @mbenoni7397
      @mbenoni7397 8 месяцев назад

      You can already do that with CollectionsMarshal.AsSpan()

  • @JackoCribbo
    @JackoCribbo 8 месяцев назад

    Nick's on a mission to one up each .Net 8 video with something having even more terrifying possibilities.

  • @bluesillybeard
    @bluesillybeard 6 месяцев назад

    Surprisingly often I find myself needing to call a method that isn't in the public API of a library.
    It's usually a method that should be public, but the creator of the library thought otherwise or just accidentally wrote the wrong keyword.
    Using this will be a lot easier than using reflection, so I consider it a bonus. Plus, I imagine it works with AOT too (since it links at compile time) to make reflection-like things possible for anyone using AOT.

  •  8 месяцев назад +14

    My prediction is that in a few years c# documentation will be bigger than the bible. The fields and classes will have some 15 keywords to define them. I'm now waiting for AI related keywords to brought into the language. 🎉🎉

    • @peanutcelery
      @peanutcelery 8 месяцев назад +4

      Right there are so many methods and properties added every update. I came from Java and I’m like damn this language updates slow but then I came to C#…

    • @solovoypasando
      @solovoypasando 8 месяцев назад +1

      @@peanutcelery c# is moving way too fast now I understand why Java is more popular, there's no way to keep up with C# and have a life at the same time

    • @cgeorgescu72
      @cgeorgescu72 8 месяцев назад

      Yeah, it will be like:
      [ChatGptImplemented]
      public partial int GetWeatherForCity(string city){}
      and will automatically fill the method body for you at build time. And will write a personalised resignation letter as well.

    • @Yudikab
      @Yudikab 7 месяцев назад

      @@solovoypasando hell yaa.i moving to open source soon enought

  • @metaltyphoon
    @metaltyphoon 8 месяцев назад +4

    If all the reflection based methods on the BLC gets to use this feature under the hood, then most reflection code can be AOT compatible

    • @Alex-ABPerson
      @Alex-ABPerson 8 месяцев назад

      That doesn't really work because the parameters on the attributes need to be _constant_ - while reflection obviously only knows what strings it's getting when it's executed.

  • @kelton5020
    @kelton5020 8 месяцев назад

    I dig it. I think this makes a lot of sense for them to iterate and improve all aspects of the ecosystem, instead of just neglecting the unsightly parts.

  • @IllidanS4
    @IllidanS4 8 месяцев назад +2

    I love nothing more than ways to break guarantees in a runtime (but readonly fields were modifiable before using... ways). Anyway I feel your performance benchmark is missing the case when you call the method via a delegate, as that is the "proper" way of binding to it (as opposed as Invoke having to perform argument unboxing and whatnot before getting to the method). Perhaps throw a function pointer into the mix as well.

  • @Dimich1993
    @Dimich1993 8 месяцев назад

    It's great and your videos are great.

  • @user-dq7vo6dy7g
    @user-dq7vo6dy7g 8 месяцев назад +1

    This can help to fit or fix problems in 3rd party components when you have access to the source code, but you don't want to build your own version just to change that one read only value to activate tls or something like that.

  • @MrDragnil
    @MrDragnil 8 месяцев назад +1

    Could be useful for certain testing situations as well.

  • @JorneDeSmedt
    @JorneDeSmedt 7 месяцев назад

    Seems useful for unit testing your private methods.

  • @jcmorin2007
    @jcmorin2007 8 месяцев назад

    I would like to point that in my code I'm using reflection for calling public type in some cases where I don't have instance of the class, but just the type. (static fields for instance)

  • @fredericbrown8871
    @fredericbrown8871 8 месяцев назад +1

    I think it can help write more robust and cleaner code when you have to use reflection anyway (assuming type safety is enforced for the extern methods of the caller class). However I would be warry of accessing, let alone setting (especially if read only), private members. I guess there might be edge cases I'm not thinking about that justify it, but unless it's for the purpose of diagnostic it feels antithetical to encapsulation and the safety it provides and looks like looking for trouble to me.

  • @hichaeretaqua
    @hichaeretaqua 8 месяцев назад +1

    I think this is a good approach to access private things if there is no other way. But I'm glad we have code reviews and hope tampering with private things never gets through...

  • @peryvindhavelsrud590
    @peryvindhavelsrud590 8 месяцев назад +1

    Have had to access internal methods from external APIs previously, this would have made that experience easier. Looks a lot like calling external APIs in the.net 3.5 days, so its at least consistent with how interop code was written to get access to hardware drivers etc.

  • @knifekitty_ls
    @knifekitty_ls 8 месяцев назад

    can you get static field of Method() and replace it with new Func that has completely different implementation?

  • @the-niker
    @the-niker 8 месяцев назад +4

    Ooof.. I sense a major rewrite in my future. How is the compatibility with older .NET7 or 4.8, can you multitarget to those and compile or do you have to #if NET8_0_OR_GREATER and write the reflection version anyway?

    • @Daniel15au
      @Daniel15au 8 месяцев назад

      This is likely a compile-time feature, meaning it should be possible to compile to a .NET 4.8 target. I haven't tried it though. It'd likely just compile to the old-style reflection code when targeting older runtimes.

  • @PeteSauerbier
    @PeteSauerbier 8 месяцев назад +2

    Can this be done with extensions as well?

  • @dadcraft9949
    @dadcraft9949 8 месяцев назад +5

    Did you know that if you cache an open instance delegate instead of the MethodInfo you can get the same performance with "reflection" (actually with a delegate) that you see with the UnsafeAccessor? All you have to do is call CreateDelegate with a type argument that accepts the target type as a parameter, in this case Func.
    var testInstance = new Example();
    var openDelegate =
    typeof(Example)
    .GetMethod("Method",
    System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)
    .CreateDelegate(null);
    var name = openDelegate(testInstance);

    • @nickchapsas
      @nickchapsas  8 месяцев назад +8

      I do, and I have made a video on it. It's not quite the same performance and it can't be JITed the same way either plus its usecases are quite more limited, but it's very close

    • @SimpMcSimpy
      @SimpMcSimpy 8 месяцев назад +8

      That is not the point of this feature. This was added for AoT compilation. Reflection in general doesn't work well with AoT, this is sort of quick patch for such cases.

    • @dadcraft9949
      @dadcraft9949 8 месяцев назад

      @@SimpMcSimpy yeah I'm not recommending anyone should choose this approach (for anything ever, really). I just think it's worth knowing about if you are stuck with legacy reflection code and need to optimise it. It's odd to me how many performance focussed articles and videos will measure reflection performance without touching on how trivial it is to boost the performance to match a virtual method call in many situations.

    • @SimpMcSimpy
      @SimpMcSimpy 8 месяцев назад

      @@dadcraft9949
      You are correct. I saw that in many articles :)

    • @DynamicalisBlue
      @DynamicalisBlue Месяц назад +1

      Thanks for this. I'm using cached reflection for something at the moment. I also thought of creating a delegate for performance purposes, or at least some reference to an actual native method but I couldn't figure out how to do it. I didn't know there was a method called CreateDelegate this entire time.

  • @RobinJohannesson
    @RobinJohannesson 8 месяцев назад +2

    That is awesome!
    But how does it work underneath? How do UnsafeAccessor attribute know what type I am using? And what happens if I have two instances of the same class, but with different values? And what happens if there is multiple functions with the same name?

    • @TheMonk72
      @TheMonk72 8 месяцев назад

      My guess is that the "extern" keyword is doing all the heavy lifting here. In previous versions of the language it creates code to call a library method. Looks like they did something similar here except the compiler just inserts code to call/reference things you normally wouldn't have access to.

    • @GumbootMan
      @GumbootMan 8 месяцев назад +1

      @@TheMonk72 Good guess, but nope, the compiler is not involved. Rather, this feature is implemented in the JIT -- it sees the [UnsafeAccessor] attribute and generates the appropriate IL to call the method or get a reference to the field. If the target method/field is not found, then it generates code to throw an exception instead. (This actually explains why getting the name wrong is not a compiler error -- can't trigger a compiler error if the compiler is not involved!)

  • @leowong9885
    @leowong9885 29 дней назад

    Thanks for introducing this new feature. I am wondering what is the motivation behind it. If authors of classes want people to have access to protected/private methods/fields, would they have not marked the functions or fields public instead?

  • @iam3yal
    @iam3yal 8 месяцев назад

    I've read various comments that essentially say that this kind of mechanism defeats the purpose of access modifiers so I hope my explanation is going to help and clarify some of that confusion or misconception, as strange as it might sound to some people access modifiers were never designed as a permission system but as an encapsulation mechanism to control the visibility of different parts of the system not to prevent it, this concept exists in programming mainly for maintainability and usability, e.g., the engine of a car is hidden within the engine compartment whereas the hood is restricted. Point is this mechanism of .NET 8 to access members (and soon types) changes nothing people that wanted/needed to access your code before could always do it through reflection or more hacky alternatives depends on the language/platform so if people are using access modifiers to restrict developers from code that is actually sensitive data then they are using the wrong tool for the job.

  • @Noceo
    @Noceo 8 месяцев назад +1

    This is gonna result in some fun code bases to maintain in 3-5 years from now...
    (I do see a case for debugging, learning and fiddling around with stuff, but never for production code)

  • @ja_mcito
    @ja_mcito 8 месяцев назад +6

    Maybe it's just for use in highly optimized libraries

    • @SimpMcSimpy
      @SimpMcSimpy 8 месяцев назад +3

      Perf is only one reason but no the main one. It's mostly for AoT and code trimming scenarios where reflection can't figure out what to take out or what to leave.

    • @Daniel15au
      @Daniel15au 8 месяцев назад

      ​@@SimpMcSimpyThe property name is still a string though, rather than a static reference... Will this help with AoT?

  • @modernkennnern
    @modernkennnern 8 месяцев назад +4

    How does this interact with string.Empty? I remember reading that it used to be changeable but they fixed that. Does this reintroduce the possibility of changing it? It's a static readonly after all

    • @nickchapsas
      @nickchapsas  8 месяцев назад +8

      I tried. You can't set its value since its marked as a JIT intrinsict

    • @modernkennnern
      @modernkennnern 8 месяцев назад

      @@nickchapsas that's great

  • @Dimencia
    @Dimencia 8 месяцев назад +13

    This isn't the worst thing you can do in C#; most of a dev's job is finding that balance between terribleness and efficiency. Always nice to have more tools in the kit

    • @ForeverZer0
      @ForeverZer0 8 месяцев назад +3

      I agree. More power is never a bad thing, so long as their is sufficient barriers in place from doing it accidentally. As long as the user must do "unsafe" (I hate this term) explicitly, there is nothing wrong with a language supporting it.

    • @memes_gbc674
      @memes_gbc674 8 месяцев назад +1

      a wise man named terry davis has mentioned this many times

    • @ForeverZer0
      @ForeverZer0 8 месяцев назад

      @@memes_gbc674 TempleOS was glorious: an entire OS where everything occurred in kernel-space. The "muh safety" cult would lose their minds if they knew.

  • @Misteribel
    @Misteribel 8 месяцев назад

    Is this a compiler feature or a dotnet feature? That is, does it get desugared by C#, or does it work with any language?
    PS reflection is usually used with names or other member or class features nor known at compile time. Once you know it statically, like in your example, you can use existing tricks to make it as fast (cache and use delegate) as a normal method call. Of course, this approach makes certain use cases simpler, but does not replace reflection.

  • @blaaaaaaaaaaaaargh
    @blaaaaaaaaaaaaargh 8 месяцев назад

    Will this work in external code? Ie 3rd party plugins you'd otherwise have to have a license for and skip their license checks?

  • @andersborum9267
    @andersborum9267 8 месяцев назад

    It provides the same end result for the developer, but comes with a significant perf improvement; setting protected members using reflection has been a thing for years using reflection.

  • @0ceanswave
    @0ceanswave 8 месяцев назад

    Function pointers are amazing!

  • @trevorprice2490
    @trevorprice2490 7 месяцев назад

    Thinking ahead to use cases I might encounter, I'd probably add an "Unsafe" suffix to all my "Caller" method names just to add a reminder to any users about what's potentially happening behind the code

  • @hinekde
    @hinekde 8 месяцев назад

    The only thing I can think of, where it makes sense to access private members would be in tests. Microsoft has/had an way for this in their own test framework using a class I think called PrivateObject.

  • @nocturne6320
    @nocturne6320 8 месяцев назад +3

    This is an amazing feature, only a shame that you haven't included a benchmark for a compiled lambda as well.

    • @AlwaresHUN
      @AlwaresHUN 8 месяцев назад +2

      Its great till my colleagues don't know about it :D

  • @briantaylor7695
    @briantaylor7695 7 месяцев назад

    Any idea if it works with Local functions, if so that would be so useful for unit testing

  • @dimitris470
    @dimitris470 3 месяца назад

    WoW this is God-sent. I've been writing a state-machine/workflow library kind of thing, and the fastest I managed to access properties etc was with compiled expressions, which still was a lot slower than direct access. Too bad it does not support Generics yet... it would simplify many things

  • @mclifeleader
    @mclifeleader 8 месяцев назад

    As a developer and an engineering manager, I can say that as helpful as this maybe it wreaks of code smell!

  • @user-nq8ln7ps7x
    @user-nq8ln7ps7x 8 месяцев назад +1

    I wonder if it can be used with generic methods/interfaces as well? It's always pain when some libraries only expose generic methods, so you have to live without polimorthism and specify concrete generic interfaces, or create some non-generic decorators with lots of delegate generation / caching / casting. For example: Kafka producers in MassTransit

    • @alexisfibonacci
      @alexisfibonacci 8 месяцев назад

      I instead create a lightweight generic wrapper with non-generic interface implementation. Instantiate that wrapper per type and cache the wrappers in a dictionary with the Type as the key. When needed, do the lookup, call to the instance to get the work done, and move on.
      But I guess .NET 8 can simplify all of that and we get to delete some code.

  • @jongeduard
    @jongeduard 8 месяцев назад +4

    I would say it opens more ways of unit testing, and especially performance testing (since it no longer has to be slower than public calls) of your own projects.
    Generally I also really like the better philosophy that in the end a compiler should not actually limit you to do things, but can give you full control if you really demand so.
    In the end it's up to YOU as a developer to make good coding decisions. A compiler should not be needlessly childish, but help you by making make guidelines clear. By disabling private access with the normal way of calling, the message is already clear, you should normally not want to do it, since it defeats purpose.

    • @Youcef8830
      @Youcef8830 8 месяцев назад

      my thoughts exactly

  • @kconfesor
    @kconfesor 8 месяцев назад +3

    This will be really useful for mocking libraries and testing 😊

    • @cgeorgescu72
      @cgeorgescu72 8 месяцев назад

      Will be really useful for messing up with the juniors in your team: overwrite their readonly int=1 then let them struggle a day to understand why it doesn't pass the test.

  • @V123098456
    @V123098456 8 месяцев назад +1

    Very interesting but something I would need a very good reason to use.

  • @thunderdeer6073
    @thunderdeer6073 8 месяцев назад +1

    Sometimes you gotta do what you gotta do

  • @AlFasGD
    @AlFasGD 8 месяцев назад +3

    I got ill just by hearing your voice, get well soon Nick

    • @nickchapsas
      @nickchapsas  8 месяцев назад +1

      Damn I didn't know people would notice! Thanks ❤

  • @danielrdm
    @danielrdm 8 месяцев назад

    Sometimes you need to access private stuff for whatever reason. Thanks for sharing.

  • @Andrei15193
    @Andrei15193 8 месяцев назад

    Had this issue with the Azure Table Storage stub I was working on, there was no public constructor for creating a result set. I had to use reflection to get an instance although it is only a DTO. Very annoying as everything else was accessible.

  • @warny1978
    @warny1978 8 месяцев назад +1

    I see a use case. I used that use case many times.
    I have a method that I need to unit test. I also do not want developpers to directly use that method so I make it private or protected. This allows to do that without complicated code.
    Another Use Case: I have created an abstract class that keeps track of field changes. This is done with backing field not visible to the end class. This allows me to access these hidden fields without permitting a developper to use it directly.

  • @JohnAndrews_nz
    @JohnAndrews_nz 2 месяца назад

    I wouldnt use this for private, but the performance boost, often we use reflection on a "object" where we knnow that object has a property/method, that doesnt have a common interface to expose it, that this could then be used to call that public property/method to get/set that value.

  • @GTSJoeG
    @GTSJoeG 5 месяцев назад +1

    Which editor is he using? Doesn't look like Visual Studio nor VS Code.

  • @user-xo5gi3gi3f
    @user-xo5gi3gi3f 8 месяцев назад

    This is Assembly Publicizer which has been available for a long time in modding community

  • @yessenzhol8989
    @yessenzhol8989 8 месяцев назад +20

    .NET developers before:
    C++ is unsafe, so we invented delegates in C#
    .NET developers now:
    Now we can call functions in unsafe manner as C++
    Great job!🤣🤣🤣

    • @ebubekircagrsen7824
      @ebubekircagrsen7824 8 месяцев назад

      This is gentlemans, worst way to criticize

    • @jean-michelgilbert8136
      @jean-michelgilbert8136 8 месяцев назад

      LOL. This is worse than any bad pattern in C++. It lets any class call and modify private methods and fields easily. The next time I see a C# developer ranting about the friend keyword in C++, I'm countering with this 🤣

    • @JacobSnover
      @JacobSnover 8 месяцев назад

      C# has had unsafe keyword since the start, they avoid it by default to save devs from tedious operations and to be 'more safe', but it's always been there. C# is used in different applications than c++ making unmanaged code much less needed.

    • @SimpMcSimpy
      @SimpMcSimpy 8 месяцев назад

      @@jean-michelgilbert8136
      This is expected when you are redesigning JIT compiler to support AoT.
      They run into wall with reflection and trimming.

    • @KurtVanBever
      @KurtVanBever 8 месяцев назад

      Your observation is correct but I think you are drawing the wrong conclusion. Remember that the type safety was not put in place because type safety is a wonderful thing in and of itself. The main purpose behind it was the almighty dollar: type safety results in fewer bugs, so development goes faster and as you know time is money.
      As said in the video MS made this feature because there are some solid use-cases for it. You could take the perspective that they are running back to C++, and in some sense that is exactly what they are doing. But the fact is that this is all part of an ongoing, more elaborate, evolution. In the same category you will find for example CYTHON (Python running back to C++).
      I think we should get used to the arrival of new or renewed languages that will put the best of both worlds together. Transition will be like going from an automatic car to driving a stick. I think it will benefit all of us.

  • @lordmetzgermeister
    @lordmetzgermeister 8 месяцев назад

    I assumed the compiler generates the references at compile time, but according to documentation the implementation is generated by the runtime.
    How the heck is it so fast then?

  • @TheSlimshader
    @TheSlimshader 8 месяцев назад

    This is a great tool in combination with source generators

  • @samysammour9983
    @samysammour9983 8 месяцев назад

    Cool feature! Very tricky however

  • @marsgal42
    @marsgal42 8 месяцев назад +3

    This looks like one of those features where you may only need it once a year. But you'll *really* need it.

    • @tchpowdog
      @tchpowdog 8 месяцев назад +2

      This is how I feel. If you have to use this against your own code, then your design is bad. This just looks like a hack for 3rd party libraries... which I'm not in favor of. I feel like if you use this regularly, then you're doing a lot of things wrong. In my 13 years of development, I could maybe point to 2 or 3 times where it would have been nice to access private members of a 3rd party class - but there was always some other solution. I'm kind of surprised Microsoft is releasing this.

  • @kumailn7662
    @kumailn7662 6 месяцев назад

    what is the purpose of private method and field after this?
    by the we have this already in Java years ago

  • @skeggs
    @skeggs 8 месяцев назад

    Love the captioning of your opening line at 0:00
    "hello everybody I'm naked in this video.." 😇

  • @MarkRendle
    @MarkRendle 8 месяцев назад +15

    This would be even better if there were a compile-time check that ensured the target member exists, which does seem like something it could do.

    • @mortenmoulder
      @mortenmoulder 8 месяцев назад

      Instead of "Method" you could use nameof() I guess. Which you also should, because if your method ever changes name, your unsafe accessor breaks. Small improvement over Nick's example, but that's about it

    • @mindstyler
      @mindstyler 8 месяцев назад

      There is

    • @matthew_jackson
      @matthew_jackson 8 месяцев назад +1

      ​@@mindstylerWanna point it out for the rest of us?

    • @GumbootMan
      @GumbootMan 8 месяцев назад

      @@mindstyler I tried it and it threw a runtime exception (MissingFieldException).

    • @MarkRendle
      @MarkRendle 8 месяцев назад

      @@mindstyler I tried it out, there was no check, it just threw an error at runtime.

  • @jc_alpha
    @jc_alpha 8 месяцев назад

    4:17 “It doesn’t take a genius to understand that having to write something like this *every single time* is very very tedious”
    You make it sound like this is the first thing we do every morning before standup.

  • @darthruneis
    @darthruneis 8 месяцев назад +1

    I have an actual use case for this that I'm dealing with right now, but unfortunately its on Net Framework, so this wouldn't really apply. Its on an old MS library for OIDC support on OWIN, so its a good use case in the sense that the code is very mature and very unlikely to change, and also the implementation is not extension-friendly (its all private/internal, not protected and/or virtual).
    So, I guess I'm stuck with the reflection code (or copying their implementation verbatim from github).

  • @diadetediotedio6918
    @diadetediotedio6918 8 месяцев назад +2

    11:55
    Yeah, but you can do it with unsafe (in fact, something very much more unsafer than to change a readonly field, but to change the string contents itself)
    Reflection was not able to do it before? I have an impression that it could

    • @nickchapsas
      @nickchapsas  8 месяцев назад +3

      You can do anything with unsafe but no, you couldn't do it with reflection

    • @diadetediotedio6918
      @diadetediotedio6918 8 месяцев назад

      ​@@nickchapsas
      Hmmm, thanks. That probably was a mistake or false memory of my part

    • @vyrp
      @vyrp 8 месяцев назад +2

      After some quick tests, I see that trying to modify a static readonly field in .NET 7 throws FieldAccessException, but works fine in .NET Framework 4.8

  • @xslashsdas
    @xslashsdas 8 месяцев назад +1

    I dunno, since I've never seen a case where I had to actually do this and not be okay with lower performance maybe my opinion is irrelevant. But, making it easier and more powerful is like removing the safety from a gun because it's quicker to shoot.

  • @aprobinda
    @aprobinda 8 месяцев назад +1

    Thanks for the awesome demo, Nick!
    I don't think it's something that I am going to use in the near future. Plus, I am not aware of scenarios that warrant messing with private members of classes in a C# app code.
    Perhaps, other viewers would describe such scenarios?

    • @SimpMcSimpy
      @SimpMcSimpy 8 месяцев назад

      It's mostly for Ahead of Time compilation.

    • @Quasindro
      @Quasindro 8 месяцев назад +3

      Video game modding is also a good example (though modders DEFINITELY were not the target Microsoft was aiming at 😂)

    • @mindstyler
      @mindstyler 8 месяцев назад

      Quite a few in frameworks/engines like Unity. E.g. editor extension and code reuse you otherwise would have to write yourself from scratch.

  • @The_Genezis
    @The_Genezis 8 месяцев назад +1

    every time he said "the name is" I filled "Primogean" in my head. Please help

  • @sergeynosov8180
    @sergeynosov8180 8 месяцев назад +2

    Is this a good use case for private members that are made public for no other reason but to make unit testing easier?

    • @osono-io
      @osono-io 8 месяцев назад

      I came to the comments to post this same use case. This will indeed be useful.

    • @SylvanFeanturi
      @SylvanFeanturi 8 месяцев назад

      No. The correct solution is to only test public API.

  • @MayronDev
    @MayronDev 8 месяцев назад +1

    Unlimited POWER!!

  • @ForeverZer0
    @ForeverZer0 8 месяцев назад

    I am totally opposed to the thinking that "too much power" or "is too unsafe" in a language. C# suffered from this thinking for a very long time until recent years when they begin adding some more powerful features and better management over arbitrary memory. A "safe" language should have all the guardrails in place, but completely removing the ability for the programmer to explicitly bypass them can be frustrating where there is something non-standard that needs done.
    Building and emitting IL at runtime was previously the next best thing to do other than just using a different language, so I am glad to see MS putting some more power and trust in programmers.

  • @B1aQQ
    @B1aQQ 8 месяцев назад +2

    So did they add it with direct use in mind, or is it mainly for source generators?

    • @nickchapsas
      @nickchapsas  8 месяцев назад +4

      It's mainly for NativeAOT

    • @GumbootMan
      @GumbootMan 8 месяцев назад

      Yes, it's primarily for source generators. This feature is extremely fragile when used manually (since it depends on the class internals), but when used in a source generator the UnsafeAccessor calls can be tailored to exactly match the class internals, whatever they might be. For example, it could be used in a source generator to serialize all the private members of some arbitrary class.

  • @tanglesites
    @tanglesites 8 месяцев назад +1

    This breaks encapsulation. What use cases does this have?

  • @rade6063
    @rade6063 8 месяцев назад

    Great video! Quick question are you using some kind of theme for rider or is this new UI?

    • @mikkirefur
      @mikkirefur 8 месяцев назад

      that looks VS Code to me. but just a guess

    • @chris-pee
      @chris-pee 8 месяцев назад

      @@mikkirefur this hardly looks like VS Code, and you can see Rider's logo in the corner. It's their new, redesigned UI

    • @rade6063
      @rade6063 8 месяцев назад

      @@chris-pee But new UI doesnt have bottom tabs or at least it didnt have them and there is no text like terminal or git its just icons as far as i am aware

    • @mikkirefur
      @mikkirefur 8 месяцев назад

      @@chris-pee thank you. i have been relegated to more devops and mgmt work lately.

  • @twiksify
    @twiksify 8 месяцев назад

    I actually think that UnsafeAccessor is safer than the previous example using reflection.
    Using the attribute; the class name, method name and kind needs to be known at compile time.
    Using reflection you can traverse and call unknown code, which I think is way more unsafe.

  • @reirei_tk
    @reirei_tk 8 месяцев назад

    Oh man, once you said the word "extern," I knew I was in for a wild ride. But then I was like, "alright, well, good thing I try to make stuff read-only whenever I can," but then you edited the static read-only field. Well, RIP to that idea. This was all pretty crazy, but that put it over the top.

  • @bachph
    @bachph 8 месяцев назад +1

    With great power comes great responsibility! 🕷