>> 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]