Introducing the .NET Community Toolkit - MVVM, Performance, Diagnostics, & More

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
>> Tune into this week's On.NET where I have my best friend Sergio on talking about the.NET Community Toolkit. This thing is going to blow your mind. It's got MVVM goodness, high performance goodness and diagnostics too. So tune in. [MUSIC] Welcome back, everyone, to another On. NET. I am your host, James Montemagno. Today I am crazy excited because I'm going to be talking about this brand new open source project called the.NET Community Toolkit. My good friend Sergio is going to talk all about it and I'm real excited because I actually did a deep dive video on my YouTube which I'll put up over there or down there on source generators, which is just like a tiny little fraction of what is in this amazing toolkit for developers building any application for any platform at all with C-sharp and.NET. I'm crazy excited. Now, before we get started, don't forget if you're over on the YouTubes, jam that like button, hit that subscribe, so you get all of the notifications whenever we put out new videos. Well, let's get into it. How's it going, Sergio? >> Hey, thank you for having me. >> Yeah, and as always because I can't even pronounce my own name properly in Italian. I can't pronounce your name. Sergio. >> Sergio. It's fine either way, I'm good with it. >> I took French for so many years and I can never roll my r's and my French instructor was just like, just give up. Then I did. I just gave up pretty much and that was it. Now this is going to be your first time on On.NET and I know that you presented at.NET Conf, but maybe before we get into it, who are you? What do you do here at Microsoft? >> Sure. So I'm Sergio Pedri, I'm a software engineer too at Microsoft. I'm in the Windows Microsoft Store, actually, Client Team. I primarily work on the client app. I also own I maintain the.NET Community Toolkit, which is this new toolkit we're presenting today. I spend my time half working on the store or primarily working on the store and then helping out in the toolkit, and then also spending time figuring out how to share components back from the store to the toolkit and then vice versa. We're trying to open source components as we can, so to also help the whole community, which is cool. I really enjoy doing that. >> Very cool. This is the store app on Windows, when I go to the store, the new one that's all super-beautiful and amazing? >> That's correct. Glad to hear that. >> I love it. I mean, my own apps are in the store too, so I appreciate that my apps actually look super-beautiful in there. >> Didn't know that. >> Yeah, I've been a Windows app developer for, oh my goodness, forever at this point. But yeah, I've had the whole journey. As soon as there was a store, I put it in the store. Now, I know that there's all these toolkits out there. There's actually been like a Xamarin Community Toolkit. There was a.NET MAUI Community Toolkit. I used to use the Windows Phone and Silverlight and WPF Community Toolkits. There used to be on code for fun and all this stuff. What is what is this.NET Community Toolkit? Is there a history here? Is it new? What's going on here? >> The project started out a couple of years ago and originally branched off from the Windows Community Toolkit, which is this toolkit that contains a whole bunch of libraries and controls and helpers primarily for UWP developers. It started out almost six years ago. Couple of years ago, I started talking with Michael Hawker, which is the owner of the Windows Community Toolkit, and I pitched a couple of ideas regarding more.NET-oriented APIs because the toolkit already contained a lot of useful APIs for UWP developers. But I figured there was also a space where we could expand to tailor to.NET developers on all platforms, both the ones actually building apps using UWP, WPF, MAUI, Blazer, or what have you, Xamarin and all that. But also mostly back-end developers, for instance. Because we wanted to have helpers and APIs that could help in all kind of scenarios. The first thing that we added was the high-performance package, which is a collection of APIs primarily meant for high performance. Containing stuff such as helpers for working with pulling arrays, working with multi-dimensional arrays in an efficient manner, APIs for pulling and reducing string instances, and things like that. Then from there, we also added the diagnostics package, which contains a whole bunch of extensions to make it easier to validate arguments and throwing exceptions into applications, which is something that's particularly verbose and also error-prone and kind of just annoying. Feels like a chore to do it, so we might try something to help out in that space as well. Then after that, I had this idea to add initially just a couple of APIs to help with MVVM because the issue was that there were a number of other libraries that already did MVVM, such as PRISM or MVVM Cross. Then there was also, of course, MVVM lite. But the issue with that is that MVVM lite was no longer really maintained and the last update was from a few years ago. And it also had a couple of dependencies specifically for like WPF and all that. Also, there's this, not really an issue, but if you start with a project and then keep maintaining it over the years, of course, you're going to keep holding on to design decisions that no longer apply at this point, even just because that may be new technologies that are better have come up, like source generators, for instance. We figured we might take that occasion to come up with a new set of APIs to help with MVVM. The idea was not to go into direct competition with like PRISM or MVVM Cross, but just to provide a set of, we say, reference implementations for interfaces and types that are already in the BCL such as I notify a property change and whatnot. Then basically to offer something that was easy to use, flexible, modular, a la carte, and not tied to any specific framework. That's how the MVVM toolkit came to life. We've kept working on it ever since. That's getting a lot of traction. I'm really happy about how that's going. >> That's really cool. This is the one that I focused on in my YouTube video, which I put a link to for like a walk-through before and after and we're going to show off all the good stuff. Because when I first saw it, it blew my mind. I know I've had a library now for many, many years that has like millions of downloads on NuGet, which is the MVVM Helpers Library. The whole idea that I had was very similar, which was there's a bunch of stuff that I want to not copy and paste around from all my different projects when I'm doing stuff. Like, oh, I just want to have a base view model or I want to have an observable object or I just want to have some optimized observable collections. It was all code that I would copy around and I put it in a library. The idea was it has zero dependencies. It's not it's not a framework, which is important. If you love PRISM, go use those frameworks that you love. But if you're just like, hey, I want to get started, this is a blank slate that you can use when you want to for certain occasions. If that's great for your app, awesome. If you need something more structured? Then there's great libraries out there. It sounds like that's the same spirit that all three of the packages have. Because they can be used anywhere with anything. >> Yes. They're meant to be independent, modular, and like even just within themselves. We took care to, for instance, in the MVVM toolkit, where we have all the various components that can also be used independently from each other. That's one of the main, not really an issue. I mean, I guess for libraries such as PRISM and MVVM Cross, one of the points is that you need to go all in. In return, you get a whole bunch of benefits such as like bootstrapping, and then you get this whole architecture for your app. But there might be scenarios where you might just want to use just commands or like just observable objects. It's kind of hard in those cases to just pick the things that you want to use and then just gradually implement more of that over time. Instead, this is the approach we took, which yes, that's reasonable to what you did as well. >> Yeah, that's very cool. Well, I'm really excited because I think I've had a lot of people ever since I did my video were like, what about your library? I said, throwaway my library, this is everything you need. Because I'm all in. I want to talk about all three packages because like I said, I've only really touched MVVM, but I want to hear it from your mouth since you and the team and the community implemented it. What are all the different parts of it and what it actually means for developers? Because you said something really important, which was, that specific library uses source generators, which is a very different approach than what I took or what other libraries out there use. Maybe something like Fody, for example, that does IL weaving. I've also got questions about that. I'd love to deep dive if you want to have a demo ready for us. >> Of course. >> You want to do it? >> I have. Let me just share my screen over here. This is the MVVM Toolkit Sample App, which basically just gives you an overview of all the docs that we have and also includes a couple of interactive samples that you can go over. Basically here you can see all the various components we have ObservableObject, ObservableValidator which are the main component model based classes that your view models can inherit from. Then we have commands. We have both synchronous and asynchronous commands. This would be the reference implementation for the ICommand interface from the BCL. Then we have a messenger which is similar to you might find in prison. For instance, they have an event aggregator or like MVVM Light had this messenger type as well. Which is a component that helps you to broadcast messages in a loosely coupled fashion across different modules of the application. For instance, you might imagine you have a module of the application where the user might log in, for instance. Then you want to broadcast the fact that this user has logged in to another component in your application that might refresh or load some additional data after that, this can be used for that. Then we also have some basic APIs to just help with people doing dependency injection and using the service locator pattern. Currently as of the 8.0 version that is currently out in preview, we basically have these two different approaches. The design decision we took with source generators was not to force developers into necessarily having to use them just because they're like new and out right now. We basically wanted to do exactly the same that we did initially, which is just letting everyone pick and choose the individual components that they wanted to use. You still have all these basic components that you expect. Then on top of that, you can also do many of the same things, but through source generators. For instance, you might inherit from ObservableObject and then implement the property normally like with the setProperty helper method. Or you can just do this by using, you can see here, observable properties and then letting the source generator do everything for you like you showed in your video. >> Let's back it up here a little bit. What you're saying is the normal observable object like in general that you have is just like a base implementation that gives you some helper methods under the hood like. >> Correct. >> Like the set property. Many developers are going to be used to this. Which is this private string name. I create my public field and then I do get in a set. But what you're saying is you can still do that or you can use these attributes on top of the code, correct? >> Correct, yes. You have both options at your disposal. Then you can just choose depending on your preference, your style or any other reason. Yes. >> When you do those properties, what is it actually doing. If you go back to those properties that you have there. >> Sorry where? >> For the observable property that you show. >> Yes. It basically generates the same thing. I can actually show you the code that's generated. I have the sample up here. You can see here that I have a whole bunch of observable properties here that also have validation. >> Let's make that a little bit bigger really quick, 160. Perfect. Awesome. These are all those those observable properties required a min length, max length those are both this validator and also just making it observable, correct? >> Yes. I'm combining both the observable property and a bunch of validation attributes. I want to set up a couple of observable properties that also need some special validation. Say you're writing some formula you want your user to fill in. >> Okay. >> If you go here into the Analyzer nodes and expand here, we put it right here. If I expand the observable property generator, you can see here there's a partial class that's the same like this one, this validation form widget view model. For each of my properties, the source generators are generating all of these boilerplate code for me. They're creating the public property and then they have a setter. Then that setter will compare the value of the property, raised the events, invoke some additional method that also let you hook into these events to like run custom logic if you want to. Then they will update the field, they then they will validate the property which will also notify the UI and then basically do all of this for you for free. You just don't have to care about any of this. You just have literally just this attribute here and that's it. Your good to go. >> I want to just like everyone, be and offer a second that that one line of code, line 29. By doing that, when you just write that automatically all of that code is generated for you 100 percent, which is mind boggling. It's optimized because you are writing that optimized code. >> Correct. There is a couple of specific optimization that you can do for instance. Like traditionally when you update a property and then have to raise the property changed and property changing events, you would need to create a new instance of the event arguments. But the thing is that if you're always raising the same event for the same property, you can basically just reuse the same instance. For instance, this is one of the things that the generator code can do for you. If you look here, when we raise the on property changing and on property changed events instead of just creating the ads, we're just accessing these generated properties. If you expand these classes here. You can see that the source generator is basically creating these classes where we just cache instances of all the [inaudible] that we use in the entire application. We just pick them up and then we use that all the time. We also have less allocations over time. >> That is pretty cool because that is something that these small little things, why source generators I think are cool is like, when I try to write code I'm going to forget to do that. Like my library doesn't even do that. Because it just like, here's a generic thing and I don't even know that this happened and that's mind boggling. Amazing. This looks like scary code but you're not supposed to edit. This is generated, you don't touch this and it's this gobbly craziness because it all these globals is to make sure there's no conflicts since it's there? >> Correct. Especially now that we have global using the in C-sharp, using global everywhere. It makes sure that even if the user has some like global using in their entire project, these types will always be the ones you expect. This code will never cause you error. >> Very cool. Now, in there, you show like this is just a property. But I know some people they may have, for example, this property also needs to notify that another property updated, let's say, if like first name, last name, and then full name or something like that. Is that a possibility to with this thing? >> Yep, of course. Let's say we had a public property. Full name like you said, that just returned. First name. You can also see that the generated property does pop up in IntelliSense like you would expect. >> Which is cool. >> Then last name. If you wanted this property to also notify this, all you need to do is just add also notified change for and then the name of that property in this case, full name. That's it. You're good to go. If you go look at the generator code again, you can see that over here. Here. We also have a second on property change, but this time for a full name. >> It was generated just literally that fast. You know what I mean? >> Yes. >> It's nearly instantaneous. >> Yeah, it's instantaneous. Because we also published our first preview of all of this stuff in the 7.1.2 version of the NVM toolkit, but this new version has been completely rewritten from scratch using the new incremental generator [inaudible] which are even faster because they are able to basically cache intermediate steps over the whole generation process so that your ID doesn't slow down even if you're working on larger solutions. I'm also [inaudible] forwarding this into Microsoft Store itself, which is not super huge but relatively large, so I definitely tell the difference when I switched to this new version. But the idea still remain perfectly smooth, even if you have all of these source generators running all the time as you type. >> That's cool. That's really awesome. We talked a little bit about required in mid-length and max-length, but that's another thing called the validators. I don't even know what that is like, what is this validator thing? >> Right. Basically this observable validator plus provides support for a type that's in the BCR, which is this INotifyDataErrorInfo. >> Never even heard of this. What? This is amazing. >> This is less known than just INotifyPropertyChange. This interface is meant to support traditionally all the scenarios where you just want to build some kind of form for the user to just fill in, so you might have a bunch of fields and then each field might need some special validation. For instance, here we're just reusing some of these that just come from the BCL, but you can also implement your own validation attribute with whatever logic you might need. Here we have this property needs to be required, this property needs to have a minimal effort two, maximum effort of 100. Here we also say this property needs to be an email address and then this attribute will automatically run some [inaudible] to validate that. This property needs to be a phone number, for instance. Then if you try that out in the sample, here, you can see that as I type like [inaudible] I can leave this invalid and you will see that as I type this icon pops up saying, ''Hey, this property needs to be at least with a length of two.'' Or like this email address, if I type an invalid email address, it will tell me, ''This email is not a valid email address,'' which is right. >> How is that being triggered under the hood? >> This is basically all done through the APIs that are exposed by observer validators. You can see here that in the generator code right after we set the field, we also called this validated property. We passed the new value of the property and then the name of the property. Then this caused an API that's from the BCL, which is a validator, and that basically uses reflection together all the validation attributes on that target property for that type. Then it will basically invoke all the validation methods that are exposed from these attributes with the new value of the property, and then it will update the state depending on that. This is also something that the observer validator type exposes for you so if you expand that, you can see that we have a property such as [inaudible] errors which you can bind to in your UIs, for instance, to display like a [inaudible] or a check mark, depending or not the form is valid. You also can retrieve all these errors or you can say, hey, just tell me the errors for this specific property, which is what the UI is doing here. If I over over here we send the tooltip just to show the errors for this specific property, and instead if I just click ''Submit,'' I will validate all of the properties and then I will show this banner. Then if I click here, it will list me all the existing errors in the whole form. >> Oh, cool. That's really neat. I need to do this because I get questions about validation all the time and I know that I can [inaudible], for example, there are some built in forms that have validation built in, but it seems like this can also, if you're doing anything in the world of [inaudible], you're showing a Windows application, but this could be done in [inaudible] it could be [inaudible], it could be anything, right? That's one thing. It doesn't matter about what you're using. It's just giving you these helper methods and generators, right? >> Yeah. That's one of the advantages of not really finding your own types for this kind of logic, but just reusing types from the BCL, is that many of the common frameworks that are out there just recognize all of these types and just support them naturally. For instance, if you're on WPF or [inaudible], if you bind a property in a textbox, the framework will automatically recognize that, hey, this target property is from a type that implements INotifyDataErrorInfo so let me also look into the events from that and then update the UI accordingly just for free. You don't have to do anything. >> Oh, cool. That's awesome. Now, before you move on to some high performance stuff and some other stuff, do you want to give a sneak peek at commands? Because I feel like commands go alongside properties, right? >> Sure. >> For people who don't know in the NVM or else, when you click that button a command demonstrates what method to call, basically, to abstract that there. >> Correct. Yeah. So we have four types of commands in the NVM toolkit. There are two synchronous ones which are relay command and relay command of T, and then two asynchronous ones which are async relay command and async relay command of T. Like you said, the point of this is to obstruct business logic from your view models into your UI. Not only that, but they also encapsulate the logic to tell the UI whether or not you can actually execute this command. So for instance, if you have a button that binds to a command, like in this case, you don't need to also hook into events or anything to notify the button when it needs to be enabled or disabled. You can just throw the commander there and it will just do that automatically. You will get the logic to update a visual state and then when clicked, it will just invoke the logic behind the command. >> Got it. >> Here you can see how that tradition is set up. So this would be in a world before source generators. So you would have a private method that does whatever logic you want to do. So in this case we'll just implement a counterm and then we expose a command that wraps this method. You can see here in the constructor I'm just creating a new instance of this command, wrapping that method. I have a sample here. As I click on this button, you can see the property's updated and then the UI reflects that. Then you can basically either do this or, like you show it in your video as well, you can also now do this all through source generators. So the way you would do that is that instead of defining the method and then defining the command and then initializing that, you can basically just say, I'm busy already doing that here actually. I have this private void method submit, and I'm saying I want this to be a command. So the second I applied this attribute, the source generator will automatically, if I expand this note here. Submit. You can see it creates a field of type of relay command, and then it also creates a property that's public where it says either give me the command that has already been initialized and set to that field or create a new one. The cool thing is that it also automatically recognizes the signature of the method. In this case, the method is just void and takes a no parameter. It knows, okay, this needs to be a standard relay command. But if that method took a parameter, then it would say, okay, this needs to be a relay command of T with that specific type. Or if the method was easing task returning then it would know, okay, I need an async relay command. We would do all of that automatically. You just need to slap the attribute on it and it would just work. >> Parameters as well? >> Yes. If I add here a string name, for instance, and then when checking for the generated code again, you can see that here now the command is of type of relay command of string and it's doing that automatically here. >> Amazing. That's so cool that it just automatically does it. It's amazing. It's mind-boggling and so cool. I love it, it's so good. Now it also renamed because your method is called Submit and it appended commands. If you went into the XAML, it'd be submit command is what will bind, correct? >> Yes, we need to still write all the docs to document this, but we have a few standard renaming schemes that we apply throughout the whole library. For instance, commands got command attached to them at the end. If they are async, we strip out the async and just append command. If this was submit async, this would become submit command. >> Cool. >> Similarly for observable properties, we expect the name to be starting in lowercase. We also support if you use m underscore it should come from the C++ world or just underscore lowercase that we recognize all of those pattern and then rewrite them to have the first character be an uppercase. >> Very cool. I love it. Now we've made it pretty far in the video here. Now, some people may have gotten this one like, this is really cool, but I'm not even doing nvm. I'm doing server development. I was here for the high performance. I'm here for the diagnostic stuff. Let's get into that stuff to be honest with you because I love nvm, I come from XAML world but not everyone's doing that. People are writing as fanatic for web apps or doing blazar applications. They're doing all cool stuff. What are these two other libraries all about? >> Right. Let me start from the diagnostics package, I guess. I have a sample here. This library contains a set of helpers to just do one simple thing, which is validate your arguments in demo. That's it. There are really just two APIs that are exposed from this package, which are guard and throwhelper. The main one is guard, which is basically just a single entry point to do all your argument validation into your methods. If you expand the type, you can see we have a whole bunch of methods here. We have a whole bunch of method to check for whether our argument is null, it's not null has a given length, and stuff like that. You can see here we have just to make a comparison, we have a sample method where we take a bunch of arguments and then we want to validate them in some way. For instance, traditionally this is how you would normally do this. You would say, if the array is null, then we throw an argument null exception and we attach some command and then some text to it that we want to check that the array doesn't have a length that's equal or greater than 10. We check that and then we throw an argument exception. Then we have another different message. Then we also want to check that the index is in range for the array and then we want to check that the span has a length that's lower than the array. We need to check a whole bunch of things and you can see how the code gets pretty verbose really quickly. It's also error-prone because an issue with all of these exception types is that the order of the parameter is not really consistent. For instance, argument null exception takes the parameter name and then the message, but argument exception takes first the message and then the parameter name. It's pretty easy to get that wrong as we write things. What you can do instead is to just use guard and all of that, get dust streams down to all of this, and which is also much easier to read. You can say, I want to guard that the array is not null, I want to guard that the array has a size less than. It's really natural-looking. You just read and you know exactly what is going on. Another cool thing that I haven't really shown here yet is that in the new version of the toolkit, we're also supporting C-sharp 10. One of the cool new features is that there's this new attribute which is called argument expression, which basically it's all of this API automatically get the name of the argument being passed here. What you can do is you can even just remove all of this, the compiler will insert that for you. All of that becomes just check that this is a size less than 10. This is in range for this array. This is a size less than whatever and then this string is not null or empty, and that's it. >> That's cool now in each of these methods and each of these guards, it throws the exception for you. Do you have control like not to throw an exception and do something else? Or is it always going to throw an exception no matter what? >> No, it's only checking and then throwing an exception. >> Got it. >> Basically the benefits of this is that they make the code less verbose and less error-prone. They also give you better performance because due to the way they're implemented internally, they make it so the final code then is implemented in such a way that all the code to create in the exception type and throwing it is moved out of your method so you get smaller method and saving binary size as well. Then also they give you easier to read and more helpful error messages. Instead of having to format all of these manually, you can see say I wanted this check to fail, so I want to call this new version and I want to say the index, for instance, is invalid as I'm passing minus two here. When I run this code, this will throw an exception. Let me expand this window. If I scroll down, you can see that the method is the parameter called index, which is an int must be in range. It gives you the previous value, the expected value, and it gives you a very detailed description of what went wrong, so you know exactly what happened. >> That's very cool, in fact, if you're if anyone's coming from the Swift World, actually, they may know about guarding as well. It's a concept I don't know what version of Swift it was introduced in. I remember I was parsing some Swift code recently and I saw these guards and I was like, I don't understand. I noticed it was a little bit different. Like, usually you're thinking, you always have been guarding you're methods by throwing these exceptions with this exception first but this guard is, oh, it's almost become like an industry-standard verb, I would say. Like you're guarding the rest of the method from anything that might be invalid, basically. >> Yeah. This is particularly useful for public APIs into your library, not just because they make it sure that you can rely better on the internal consistency of your code, but also because they can avoid getting into states where you're just in a corrupt state. Because you can imagine a method that just expects an argument instead of failing immediately, you will just start doing something and then fail at some other point later on. You might be left there with some half of the work done and another half not done, which might be in an inconsistent state, which is hard to recover from or just outright impossible. Just making sure that you fail as early as possible, right of the start of the methods makes it much easier to just debug things later on. >> Very cool. You say, there's something else in this package as well, the beyond guard. There are some other helpers in there? >> Yes, there's the throwhelper API, which is basically what the guard APIs are using internally, but just explicit. The way it works is that this throwhelper type and then these expose a whole bunch of API to throw all the common exception types so the exception arguing that no exception and all that. The point of this is that for cases where you need explicit control of when to throw a given exception type or what exact message to include, you can use this one that still give you better cogen because you're still not creating the exception, and throwing it yourself. But you letting the git compiler move it out due to how it's implemented internally. This is the same pattern that the BCL is using internally, for instance. >> Very cool. Awesome. Last one. High performance. You got to tease it at the beginning but I don't know who doesn't want high-performance code. What's that one all about? >> Right. I have the docs for that over here. Actually, I'm not sure where they are, here. This package basically contains a whole set of APIs to do, like I mentioned, things such as pulling memory from the ArrayPool, caching and reusing strings and things like that. We don't really have a sample for this but we have a bunch of docs that you can check out here at docs.Microsoft.com, or you can just browse the source code. One of the common types that we have are SpanOwner and MemoryOwner, which are basically wrappers around the ArrayPool type from the PCL. The point of this is that, say you needed a temporary buffer to do some work. What you would do traditionally is you would call ArrayPool, rent a buffer, then get a span out of it, then do some work on it and then finally return it to the buffer, which is verbose and also relatively error prone because you might just forget to return it in all code path. Instead of doing this, you can just rewrite all of that to just do, hey, I'm using a SpanOwner and I want to get this minimum length. Then from that, you get the span and go about your day. Then whenever this buffer goes out of scope, due to the fact that you're using statement here, this dispose method will just return the array to the pool automatically for you. >> Cool. It implements all your [inaudible] things for you so you don't forget. >> Exactly. Another API that we have is Span2D and Memory2D, which are similar to span and memory from the PCL, but this time they're working 2D space. They can be particularly useful when you're working with image data, for instance. Say you're interrupting with system drawing and you need to get a bitmap and then you lock it and then you need to do some work on the raw pixel. It can be a bit error-prone because you need to account for the distance due to padding between each row. You need to account for the fact that you get a pointer and then you need to cast it to the right type. Also, you need to manually calculate all the offsets to isolate, for instance, columns or a given subsection. What you can do instead is to create a Span2D and let that works exactly like a span. You can index it with the only difference being that you get two indices here because you're in 2D space. You can also slice it. You can get the reference to an item. You can get a span from a row. You can slice it into D so it will automatically internally keep track of the right offset so that you can say, I want to, for instance, cut out this frame area and just get another span that wraps around this inner part. Internally you will know, I need to trim down this bit. I need to calculate this offset and it will do all of that automatically for you. It also has a couple of helpers to efficiently iterate columns or rows by reference as well. A huge number of APIs just to help in these scenarios. >> That's really cool, especially if you're doing things like games or like you said, a lot of like mathematical computation, these can be really, really helpful. >> Exactly. The last one I want to call out is the StringPool type, which is basically a reusable pool for strings. A scenario where this might be useful is, imagine you're writing some parser. You might receive as input a whole bunch of text you want to slice and find some bits that you need to extract and then you need a string out of it, because maybe the API they need to call require a string and they don't just accept a span. The point of string is that they're immutable so you can reuse it, but there isn't really an easy way to just get an existing string with that content when you need it. This is where a string pool comes in. You can use it like this, you can just do StringPool.Shared.GetOrAdd. You pass it to span. What it will do is it will internally use that span as a key to find or create a new string efficiently with the same content and return an existing instance if there isn't. We run a bunch of benchmark over this and you can greatly reduce the amount of memory allocations in scenarios where you're heavily parsing and allocating new strings as you're processing data. >> That's very cool. I can see any of these, especially when you're just really trying to fine-tune your application and really get it super performant. These are the nice little things that you could optimize your code with. >> Yeah. >> Awesome. Now, this thing is completely open-source where people can contribute, correct? >> It is. Yes. You can find it on GitHub, CommunityToolkit/dotnet or there's also a short link which is aka.ms/toolkit/dotnet which just redirects to here. All the code is open-source over here and you can find also links to the docs and your contribution are more than welcome so you can open issues, you can open discussions and you can propose APIs, you can report bugs. If you have a new idea that gets approved, you can also go ahead and open up a PR. Just like the Windows Community Toolkit has been all this time. This is the whole point of the Community Toolkit is that it's a first-party library. It's maintained by Microsoft engineer, and we're also using first-party applications, but it's specifically open towards the community. It's a place where we really welcome people having a look and helping out in any way they want, either just by reporting bugs or just proposing ideas, and then just why not also go ahead and implementing them as well. >> Very cool. This has been absolutely delightful and amazing. I only got to scratch the surface of what's inside of the news version of this. I will put links to everything that we showed today and the blog post as well. As new features are added, you'll create some shorter videos probably for Sergio and the team to talk about what's coming new because every single.NET developer, there's something for you in these amazing set of libraries. >> Sounds like a good plan. >> Well, thank you so much for coming on, Sergio. I really appreciate it. >> Thank you for having me. >> Thanks to everyone that's been tuning in. If you made it this far, honestly, thank you so much. Of course, if you're on YouTube, jam that "Like" button, hit that "Subscribe" button, ring that notification bell, you know what to do. I really appreciate it, but until next time. Thank you so much for watching. Leave your comments below and that's going to do it for this week's ON.NET. We'll see you next week. I'm James Montemagno and thanks for watching. [MUSIC]
Info
Channel: dotnet
Views: 28,694
Rating: undefined out of 5
Keywords: .NET
Id: oKMZiDA9ogM
Channel Id: undefined
Length: 41min 20sec (2480 seconds)
Published: Wed Mar 30 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.