The New Way of Calling Your Code in .NET 8 Is INSANE
Вставка
- Опубліковано 22 гру 2024
- Use code DOCKER15 and get 15% off the brand new Docker course on Dometrain: dometrain.com/...
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/nickwor...
Don't forget to comment, like and subscribe :)
Social Media:
Follow me on GitHub: bit.ly/ChapsasG...
Follow me on Twitter: bit.ly/ChapsasT...
Connect on LinkedIn: bit.ly/ChapsasL...
Keep coding merch: keepcoding.shop
#csharp #dotnet
This is probably a crime in +50 countries.
It is also forbidden by Genebra convension!
It means we can do anything what we want to be in any framework we’re using😂
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
Mama i am a criminal...
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.
INSANE
Make sure your comments are totally off base too 😉
Truly a gAmE-cHaNgEr
WARNING *sarcasm* DETECTED
You could have done that in previous versions of .NET too. It's just become a more pleasant coding experience to do so now 😛.
I'm guessing this is part of getting rid of reflection for AOT...
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.
Interesting.. Is it because this can be done at compile time or something?
@@z0nx Exactly, I think they will combine this with source generator to generate code at compile time and not during runtime ;).
Yup Native AOT plays a big role in .Net 8
@@peanutcelerySomebody has been paying attention 🫡
"The value is Nick" - You are the value mate appreciate your work
For this feature I must say "With greater power comes greater responsibility". Excellent demonstration. Thank you Nick.
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!
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.
With great power comes great responsibility.
Don't use your power to change static readonly fields :D
Who would win: ten years of SOLID principles vs one unsafe boi?
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.
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.
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
Yes. haven't thought of that. thats actually a good use case.
@@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. 😊
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.
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.
"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.
Compile time performance is the best part of this ❤
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.
You can probably get the same perf with reflection if you compile lambda expressions
@@BillyBragayeah I think he did something like that in another video, not sure why didn't in this one
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.
absolutely agree
👀
Ideally with some multithreaded examples
It's funny seeing a comment about this because I just used this recently on a project for the first time.
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.
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.
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
In "powerful" you mean "I've done mistakes in the design so I have to break encapsulation, but I want some syntactic sugar on it so my boss will think I'm doing a good job"
You'd be better shooting your own foot.
The first place I will use it is to grab the array under List
You can already do that with CollectionsMarshal.AsSpan()
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
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.
@@leerothman2715 agreed I think we are all mostly on the same page of this can be useful but only in rare or extreme situations.
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
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.
@@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.
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
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.
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.
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
I tried. You can't set its value since its marked as a JIT intrinsict
@@nickchapsas that's great
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.
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.
That will be very useful, especially on nuget packages those not maintained anymore.
@@phw1009how would you improve the packages that not maintained anymore? Do you mean changing inners of packages or extending functionality?
@@noon9548 It could be enough to be able to access some internals to be able to work around a problem.
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.
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.
Imo reflection is useful for testing private things or to call generic methods with multiples types.
I use reflection in my GPT library.
GPT can call "tools" but need them in json format, and then calls them in json format.
What I accomplished for my library is that I can just write
//static
model.addTool(() => MyClass.MyMethod);
//instance
model.addTool(mc => mc.MyMethod2);
And converting them to json as well as finding and invoking them again after getting a json call happens in the background. This is saving so much time.
(Though I only accept public methods, didn't even think private ones would work)
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.
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.
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."
Can this be done with extensions as well?
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.
Is this a good use case for private members that are made public for no other reason but to make unit testing easier?
I came to the comments to post this same use case. This will indeed be useful.
No. The correct solution is to only test public API.
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);
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
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.
@@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.
@@dadcraft9949
You are correct. I saw that in many articles :)
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.
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
You can do anything with unsafe but no, you couldn't do it with reflection
@@nickchapsas
Hmmm, thanks. That probably was a mistake or false memory of my part
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
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
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.
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?
So did they add it with direct use in mind, or is it mainly for source generators?
It's mainly for NativeAOT
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.
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?
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.
@@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!)
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.
So you can actually use this across assembly boundaries? I remember years back sometimes running into issues with certain external libraries/frameworks that *almost* did what I needed, but not quite, and it appeared to be because of unnecessarily restrictive access modifiers. Ah, it was so frustrating. I wonder if this would've helped me, if I'd had it at the time..
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.
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.
Which editor is he using? Doesn't look like Visual Studio nor VS Code.
Does this work for with the BCL too? If so, then it makes all of the BCL virtual, seemingly.
what is the purpose of private method and field after this?
by the we have this already in Java years ago
I guess this enables you to test private methods (which isn't really necessairy unless you develop BIG methods with multiple tasks combined). Is there any other use case for this?
Exactly my first thought as well
There are many ways to write code but only a few produce code that is easily testable. This can be quite helpful for badly written legacy code I suppose.
If your methods have multiple tasks combined, they're too large and should be broken into smaller methods. Ideally private methods are implementation details that don't need to be tested on their own.
FYI Microsoft is planning to use this feature to enable the built-in JSON serializer to deserialize private members in source generation mode (in a way that is compatible with NativeAOT).
@@Daniel15au My point exactly.
Any idea if it works with Local functions, if so that would be so useful for unit testing
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.
It's really helpful feature in some rare cases. Thanks for the sharing.
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?
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.
Nick's on a mission to one up each .Net 8 video with something having even more terrifying possibilities.
This makes me wonder if it would have a place in testing. Sometimes I want to access a value that should be private so as a work around I would change it to internal and allow internal access to the test project. With this new code I'm assuming i could leave it private and still access it?
You should never perform behavioral testing, like exposing its inner components and testing how they are adjusted behind the scenes. You should only care about the exposed side effects, your current public state and whether your code does what it is supposed to do. If you feel like you have to use this during testing, you are either doing something unsafe in nature, or you are simply not doing something good and need to test something more important.
@@AlFasGD While I agree, I can think of a use case for testing. Large old crappy code bases that weren't written with tests in mind. Classes that don't follow SRP, but have private methods that go and gather data and such. If they work well enough to not warrant a rewrite but could use some unit test coverage... I would want to think about it longer but the potential...
@@rab1d78 Legacy codebases are always the exception to the rule. That's the scenario that this feature is primarily intended for; legacy systems and libraries that barely hold things together. Writing tests even for observational purposes could also help ensuring that you know what to expect in certain scenarios.
@SchadenNZ yes sure. What I usually do is create a source generator for my test project, that creates private method accessors through reflection.
With this new UnsafeAccessor you could do something similar
@@AlFasGD Theory is all well and good but try working on a code base that is over a decade old, was written without any consideration for testing, has been modified so many times that no one knows the purpose of large sections of code, serves half a BILLION requests a month with a $10k per minute SLA penalty --- and the ticket wants you to add a few tests to increase confidence all the while changing as little as possible.
Don't expose inner components is so far down my list of priorities that I'd have to take an elevator to get there. 🤹
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.
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.
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)
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...
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
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.
a wise man named terry davis has mentioned this many times
@@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.
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.
That's great, but what if you also cannot access the object type directly?
can you get static field of Method() and replace it with new Func that has completely different implementation?
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.
Could you give examples of when we MIGHT need to access a private method ?
Unit tests
One great example is modding Unity games!
Although when modding you'd probably use a fake assembly as ur reference, so the compiler thinks that everything is public (lookup NStrip)
(yeah this didn't age well)
@@arjix8738 "so the compiler thinks that everything is public" are you talking about injecting code into the unity process? because I still have to use reflection to access private variable if I am injecting.
@@arjix8738Assembly Publicizer has been my go-to for the same purpose, but I see NStrip is made by the BepInEx creator so I will give it a look too!
Do somewhat wish this new API existed back in .net 4 or something so we could use it instead of publicizing all members (I much prefer the idea of only publicizing those members I need rather than everything - less footguns that way!)
I would have preferred an Attribute to this. Though it is still a step in the right direction. Roslyn has/had something similar with the [assembly: IgnoresAccessChecksTo("assemblyName")] Attribute. Wonder if the boilerplate can be source-genned away or some notification can be shown if the member you're trying to target no longer exists.
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.
Nice, another footgun! It's almost C++ now :D
I think that the only thing that's missing is pointer arithmetic?
I wish.
I'm currently on a C++ and a C# project. Whenever I'm on the C++ project, I miss reflection. Whenever I'm on the C# project, I miss being able to do what I want.
(The thing I hate the most about C#, is not being able to treat a nullable as a bool. Let me do `if (someNullable)` Please!
@@SylvanFeanturi To be fair, pointer arithmetic is generally unnecessary in truly modern C++ (I'm not talking 90s-style C++ here).
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.
Wasn't this (type analysis in extern DLL) always there? How is it new to net8?
Maybe it's just for use in highly optimized libraries
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.
@@SimpMcSimpyThe property name is still a string though, rather than a static reference... Will this help with AoT?
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.
Probably going to be eons before Unity updates to .NET 8 (if its even around then given their current dramas), but when it does, this will really change editor scripting for the better. So many useful methods and classes are needlessly internal or private, resulting in tons of required (cached) reflection or even IL emission to do anything even remotely advanced.
...and if we're lucky, they'll only charge developers $150 per .NET major version!
Unity is dead even with their new price change as trust is not adressed.
Try Stride instead they're reasonably up to date with their .NET version.
Some people still haven't moved to Unreal/Godot yet?
Unreal exposes a lot and lets you override almost everything, and for the very few things you can't, you can modify the engine directly.
Can't speak for the exposedness of Godot but at least it's open source so you can still do what you want.
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).
As a developer and an engineering manager, I can say that as helpful as this maybe it wreaks of code smell!
Will this work in external code? Ie 3rd party plugins you'd otherwise have to have a license for and skip their license checks?
Love the captioning of your opening line at 0:00
"hello everybody I'm naked in this video.." 😇
But why does it need you to pass an instance when you're accessing a static member? edit.. right.. it needs to know on what type..
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
This breaks encapsulation. What use cases does this have?
Nice! it is something that I probably only use in my unit tests!
I saw Zoran Horvat do something like this for field mapping with Entity Framework. It being private makes it clear that it's not part of the model API was his reasoning.
So I have a private var inside my class, and I 100% trust it only holds 1 of 4 values that my method calls allow. But now it might be any other value too. How on earth is safe and tested code possible with those kinds of rules at play?
If someone messes with your code and changes the private value to something unexpected and it breaks, it isn't your job to support them beyond saying "yeah, don't do that."
Using reflection and other means to access private members have existed in .NET for a long time, there is nothing you are seeing in this video that wasn't already possible some other way. It's just a new API for doing it with the same performance as it it were public, and that's already possible, via even more unsafe means.
So, treat private the same way you always have. Most users of your libraries etc. won't ever think about trying to access private members, and those that do will almost never come crying to you about it if they break something in the process, because they should know better.
I got ill just by hearing your voice, get well soon Nick
Damn I didn't know people would notice! Thanks ❤
Is compiler able to detect missing method in compile time? The most pain to me on reflection is maintaining someone's else code based on reflection.
no
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.
This will be really useful for mocking libraries and testing 😊
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.
Kinda OK with having this. Just yesterday I had to use some internal setters for tests involving types of the blobstorage lib. But allowing this to break promises like static readonly seems to me *absolutely bonkers*. Really.
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.
my thoughts exactly
This is an amazing feature, only a shame that you haven't included a benchmark for a compiled lambda as well.
Its great till my colleagues don't know about it :D
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
Can you use this to do unit tests on private methods?
why would you want to? A class is the unit, private methods should not be tested like that - you test the public API, the only one you use.
Could someone help me to explain why 10 years before They referred to use the of reflection?. It's really painful to debug in the huge system.
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?
How are you able to set the value of Field by calling the function and then assign 'John' to it? Could someone explain this?
Because it’s a reference due to the use of the ref keyword
@@nickchapsas i see. So having the ref keyword would allow the function achieve the same purpose as something like propertyInfo.SetValue(Example, "Nick")?
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
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.
Wonderful insights, thanks!
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.
Could be useful for certain testing situations as well.
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.
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
There is
@@mindstylerWanna point it out for the rest of us?
@@mindstyler I tried it and it threw a runtime exception (MissingFieldException).
@@mindstyler I tried it out, there was no check, it just threw an error at runtime.
Well, but this uses attributes. So the method name has to be hardcoded, right?
Yes, but you have to do that with reflection approach as well. So no difference compared to the old way.
@@SimpMcSimpy The GetMethod receives a string as a parameter which can be a variable. If you do something dynamic, you can pass a computed value there. On the attribute you can't as far as I know.
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.
How does it compare to expressions performance-wise?
It’s faster
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)
Very interesting but something I would need a very good reason to use.
Might the reason of introduction of such logic was better support of Roslin-like compilations, as in case of Reflection those examples just wouldn’t work?