Nullable Reference Types - The Good, The Bad, The Ugly

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
once upon a time in a galaxy far far away from here there was one thing that all.net developers agreed upon and that was that the reference types can have null as a value and everything was clear we all knew what we need to do we did a lot of null checks and everybody was quite happy but then nullable reference types hit us with c-sharp 8 and suddenly everything became more confusing what's up with all of those question marks what's with all of those exclamation marks but there's light at the end of the tunnel because in this video I want to lay down a very big picture of notable reference types it means not concentrating only on the beautiful part but also going into the more ugly part of nullable reference types so stay with me [Music] thank you hey there and welcome to the code wrinkles channel in this video I want to walk you through what nullable reference types are but actually more than that the biggest problem with multiple reference types is that everybody is only talking about the good parts that it solves but virtually nobody is talking about the bad parts or even about the ugly parts of that so what I will want to do here in this video is I want to walk you through exactly what's in the value that nullable reference types bring us but also the challenges the headaches the pain that we all get as developers when we want to transition from let's say a previous mindset of developing with.net to the new mindset that we need to have when we want to use nullable reference types so first let's understand what notable reference types actually bring to the table I've set up a very basic demo application that will walk us through what nullable reference types can actually do for us but also showcase the challenges that we might have when we want to use this feature and I have set up this very basic chess player class which is a model and entity that you would have probably in most of your applications so we have here a chess player ID and then we have some strings like identity ID first name last name description and we also have this chess player rating class which is our own class and we call this rating now you can already observe that all these properties kind of like they are underlined with this orange line which means that there are some warnings and those warnings are specific or due to this idea of nullable reference types what I would like to show you to actually get a sense of what nullable reference types are here to fix I have this very basic setup in the weather forecast controller here we have this just player we instantiate a new instance and then we kind of like want to get the blitz rating for that specific player and then we want to lock that information now let us run the application and see exactly what it happens when we make a request to that API now we have a running application so I will execute the request and as I executed the request you see that we got this exception which is of course a null reference exception and we see that okay object reference not set to an instance of an object and I think that s.net developers this is probably the most common exception that we get and what we end up doing is usually pinpoint all the places throughout our code where we might get this type of errors and place everything in null checks so in this case we would kind of like let's move this away we will kind of like move here and say that hey if this rating is null like if on the player the rating is now then we probably will not lock this so we'll wrap this this basically in a null check and that's precisely exactly where nullable reference types come in because what they help us achieve is actually avoid this type of null reference exceptions let's see how that would work let's go back forward to our chess player for instance and let's take into consideration that hey this might be nullable you can set basically all the properties is in the class that they are knowledgeable reference types by just placing this question mark like we did here now if we go back to the controller right now what we'll see is that we get here in this case some warnings and the warning is obviously that hey rating might be null here now there is a way to actually do this and we can simply say okay if the rating is not null then I would like to get this property and let me run the application once again and see exactly what we get back at this time the application is up and running so let's execute a request and in this case we see that we haven't got that null reference exception instead we got this logging that hey player rating is null now this simple or this very simple feature the notable reference types as you can see already can help us a lot because it avoid us having or getting those null reference exceptions we as.net developers have developed a lot of different ways to do null checks and suddenly with this nullable reference types we have the possibility to actually get rid of all our null reference exceptions that we use to get in our code so imagine what the future of our applications would be without any null reference exception at all that would be certainly great however there is one big problem or one big challenge actually that comes with this and this is the challenge of consistency talking about consistency our application right now is not consistent at all because what we do here in the controller is okay we have to solved this problem all this null reference exception fall for this rating property by introducing this as a nullable property which is fine so we have used this notable reference types idea but then for all the others we don't do this so this is not consistent right now if anywhere else in the code I will I would use the identity ID or the first name or the last name or the description with a very basic chess player instantiation I would still get a null reference exception and that's something that we need to solve so consistency is actually very hard to achieve because as long as we work with warnings or as long as we get these warnings for nullable reference types there's also the possibility that we kind of like leave something out and suddenly our application becomes unpredictable and the consumers of our code will not know anymore that's this piece of code use notable reference types correctly doesn't it use them correctly so people get confused and when there is confusion then there's also place for bad application code now the idea is that to introduce consistency in applications where we say hey we want to go with nullable reference types all the way there is or there are a lot of things that we can do about it and I would like to mention a very nice blog post that I have read recently from Christian Findlay Christian Findlay is actually from Australia and is a guy that I follow on Twitter and it happens too that I like him very much because it has a major in philosophy just like me now the idea is that in his article which by the way I will leave a link down in the description of this video he exposes a step-by-step procedure to which you can ensure consistency when it comes to notable reference types in your application and the first step or one of the first steps to achieve consistency when it comes to multiple reference types is to actually treat the warnings as exceptions not only conceptually but really we have a way to do this in our project so to be consistent let's go and implement this approach so we want to treat the warnings that we have right now as errors and this will assure that our project will not compile as long as we don't adhere to the whole notable reference types of stuff so let's right click the project and here I will go to edit and I will edit the Cs first file and here in the project group I will add something like this treat warnings as errors equals to true now this is the easiest way to achieve this but it's actually probably in production applications not the best one because that will treat really all warnings as errors not only the null reference types errors but there is an extensive documentation on learn.microsoft.com that explains exactly what options do you have to actually configure exactly what warnings do you want to handle as errors and I will leave a link to this Microsoft documentation in the description of this video so you might want to check it out let me just close this and as we have done this we see that we already have some errors the first thing that we need to do when we want to fix these errors and think and think in terms of nullable reference types is are my properties or are these types really nullable or not like do I want to always have a value for those properties or is it acceptable in my application that those or that these properties in this case are not and that's the question that we as developers never ask ourselves so often before we had this notable reference type feature so if we look a little bit here we have this identity ID that it would be presumably something that's related to asp.net users or probably from Microsoft asp.net core identity perspective and that would be a geoid and I would say that yeah if you can if you create a new chess player well it needs to also have an identity ID and then what we can also do is we can have here this first name is it required like obviously if I have an application where users are able to create accounts I would like for them to have a first name that would probably also like for them to have a last name last but not least this idea of description so that's something that's kind of like optional so well I can accept users or chess players in my chess playing application that don't have a description so I just I am just interested in their first name and in their last name now that we know conceptually exactly what is acceptable to me to binal and whatnot let's see how we can solve this now the first thing is we on this description we can just go on and click here this question mark because this is nullable so we accept nulls here now we have to solve the problem with all the other warnings so let's go on and create a Constructor now what we will need here is for instance to take in a string first name we will take a string last name okay so we have solved the problem with first name and last name and the other thing is that we have this identity ID now the identity ID we don't want to get it as a Constructor parameter so what we'll do here is that we'll see identity ID equals qid new guid and then the string so it will turn this into a string so now we should be good to go now we don't have any errors anymore at least on this class here but we have some errors here on this controller and that's obviously because we want the Constructor so we have said that we want a Constructor so let's go on and Implement everything that we want in this Constructor so it would be let's give it a first name I would use for the last name code wrinkles and then we could we would be good to go our application is now consistent and that's really already a great achievement but then what would be the next step that we would like to do in the application of course we would like to persist this chess player that we have created so far in the database and in our case we are using Entity framework core and this is precisely the point where we start to face challenges or when we start to actually see the ugly parts of nullable reference types in practice therefore the next thing that we would like to do is to add a migration and I have already an application DB context here so we would be good to go still I would like to do a change here because it's very important in the context of this entire topic so let's for instance assume that the names of this incoming parameters are not first name and last name but our fname and L name and let's just use this one here and also use the other one here now everything is still okay from the perspective of how the code works and there is a very important reason why I did this now the idea is that Entity framework core by default if it finds incoming parameters that match basically the name of some properties and you set them in the Constructor it will simply add them so you would be able to have this type of Constructor and everything would work however the instant that you change something for instance and the parameter name doesn't correspond to a name of properties or to some names of the properties then Entity framework core will actually throw an error and we'll see and we'll take a look at the error just in a few seconds and the reason why I think is this is important is because in most applications like real applications that we build for our customers for reproduction purpose Constructors are not always that simple and there are a lot of cases where you would have to take and Constructor some more parameters so instead of cluttering The Constructor here you might simply just use an own object that contains all the information that you need for for that Constructor anything similar to that now if we go to an Entity framework core and I have here in the tools and the framework core and migration and I would like to add a migration and we got this error here this exception and if we scroll up a lot we see that no suitable Constructors found four entity type chess player and that's an exception that we always or that we very often get when we work with Constructor and Constructors edit the framework core besides that also this problem with identity ID that I set here always to a new guid is not really very very nice because it's not very clear always if that will be overridden by EF core theoretically it will be but still I I don't like to have this here bottom line is that when we are using anti-frame or core for instance we cannot really rely on a Constructor so that we can Define values for the properties that are not nullable and that's a big challenge for us because we have to rethink the entire model that we have here because we you want to get rid of the Constructor okay good but what do we do instead now we would have a bunch of different options to handle these type of things the first way to do things would be to Simply well initialize the properties to some default values and that's also let's say similar to a concept that's known as a null object pattern so instead of setting something to null we just set something like a default object now for this identity ID we could set as a default object this guid the new guid and then this tostring method and then for the first name and for the last name we can say say here string dot empty so that it would need to be empty as a default or if you can go here also you can string dot empty and here there is a discussion that I also want would like to go into because I have purposely used this example because I have seen it in different blog posts now from my point of view this is not really okay so instead of using hero string dot empty well I would prefer to maybe use any other possible approach but still string.empty instead of null from my point of view is not really a very big Improvement now the cool thing about this is that if you're using c-sharp 11 then you have even another option which is cleaner to actually Define that hate these properties need to have a value and this is the required keyword so we can see here that public required string first name and public required string last name and in this case what it will happen is that we are obliged to set some values for the first name and the last name either in a Constructor but okay we don't have a Constructor but we can set those values also in the object initializer so what we can do instead here is we can come to this controller because now we have this error message we don't have this Constructor anymore but what we can do here is replace this Constructor we should written object initializer and here I can see stated for the first name I can provide my name and for the last name I would provide then the name of this Channel and now theoretically we shouldn't have any error so if we go back we see that everything is correct now that we have this behind of us there's still some other thing that I would like to discuss when it comes to Entity framework the problem is though that this chest player rating we are using actually as a navigation property when it comes to navigation properties this brings us to take a lot of other things into consideration like for instance when this data is loaded because when the data is retrieved from the database if we haven't include that also includes the chess player rating then it will never be null but if it doesn't include it then this chest player rating will be null so you see that we kind of like have here a very Dynamic scenario where this just player rating might actually be null in some scenarios and will for sure not be null in other scenarios we could solve this through different weeks now one of the options would be to send this to null and to use this exclamation point which is also called the null forgiving operator and the non-forgiving operator just tells the compiler that hey here's a value but this will never be not so what we are doing here is kind of feel like we are lying to the compiler that we want to set it to null but it's not null so yeah that's even a moral question if it's okay or morally acceptable to lie to the compiler but the idea is that well we need to find some this type of workarounds if we are going all the way with notable reference types throughout our project and if we work with Entity framework and things are not finished here when we think about Entity framework core so if we go back to the appdb context we see that we still got an error here like and if we hover the mouse over the over this FDB context non-nullable properties chess player is uninitialized now the problem here is of course that we have a DB set of chess player and this is not initialized we have a Constructor but we don't initialize it in the Constructor the only thing that we do with this Constructor is that we pass this DB context options to the base Constructor now the thing is that this is something that Entity framework core handles and any framework core always warranties that we will have an instance of DB set even if it is empty it will still be an instance so we don't really need to to initialize this ourselves here so this is once again a place where we would be well necessary to lie to the Constructor and simply set this to now and choose the null forgiving operator to say hey now it's actually not really null it's something so a first conclusion on using nullable reference types in our application is that when it comes to EF course at least we might have some additional challenges that we need to face and the bad part of this is actually that resolving these challenges or overcoming these challenges might imply using some very weird and strange workarounds like lying to the compiler why would we even want to do it but still if we want to do this all the way we need to make these kind of trailers however you have to know that working with Entity framework core and nullable reference types is not really the only problem there is also another very common scenario that I'm sure you encounter a lot or will encounter a lot in your application and this is dtos in conjunction with nullable reference types what we have here is a very basic chess player dto that has a first name and last name and a description and we have annotated the first name and the last name with this attribute required which is actually very important because here I have also reworked a little bit this weather forecast controller and here I have this one post method and we have this test player D2 now the thing is that when it comes to model validation and model binding the way that we are used to doing to do things to annotate our details with this type of attributes like required this would guarantee us that the model state will not be valid if those properties are not set so this will guard us all these null reference exception because if we enter this execution Branch then it means that our model is valid and our model in this case clearly states that the first name is required and that the last name is required so we are fully guarded against another reference exceptions just by using this model binding feature in the asp.net core API but what I want to show you is that there is also another way to get rid of this type of errors in in objects like our details here that clearly don't really have a value because we have already the model stated the other Edition for us one other thing that we could do is just simply annotate this file with the nullable disable and if we annotate it with nullable disabled this will turn off the nullable context on this specific file and this will make all our errors go away so once again we are forced to find very weird workarounds to actually get our details working with this concept of notable reference types do you think we're ready no not really yet here is yet another scenario that or where we could have some challenges when we want to apply nullable reference types and this is Razer Pages here's another application that I have created during some live streams recently where we have created or started to create a basic chess playing application with blazer server however we also wanted to have authentication and authentication in Blazer server we usually actually do throughout Razer pages so we have this razor page for login that contains of course the login model now the thing is here on the Razer page is that we have for instance this input and right now as we can see we have a warning here on the Constructor but it clearly says that hey we have the input the return URL and the error message that they are not set here in this Constructor so it's exactly because those properties if we take a look at them they are not really well specified as is nullable now for the return URL we could specify this nullable for the error message we could also maybe specify as the specify it as nullable however for the input it kind of like doesn't really make sense because the problem here with with the Razer pages is that you have one page model and you have this input model that you use but for the get when we have a get for the login page this of course will be null because we don't need it anymore but when we make a post this will never be not and we also have here input validation or model validation so if the inputs don't correspond to what we specify basically in the input model itself then of course model validation won't go further and it will return an error message so it's kind of like exactly the same scenario that we had previously also with details also with Razer pages and once again will probably end up doing something like okay coming here and let's see notable disable and then we would get rid of all these type of messages that we had earlier and by the way just to give you an example this is actually this cool behind file coming from Microsoft asp.net core identity so the official Microsoft package for handling defaults are very simple identity scenarios and by the way this page comes if you scaffold it by default with nullable disable because it doesn't really make sense in the context of Razer pages to annotate or to think about this type of inputs is being notable or not because or the answer to these questions would be different depending on if you are getting the page or if you are posting the page now that we know all the challenges that we have in Brandon projects with knowledgeable reference types imagine what would happen if we would like to transition to nullable reference types in an existing code base that might be already be huge now in that case I would have just a few pieces of advice for you transitioning to another reference types in an existing code base that's also pretty large is not something that you actually can do in one go so the way or I think that the best way you might want to do this is to First enable nullable reference types at the global level in your project but then add this knowledgeable disable on all existing code files so that you enforce the proper use of nullable reference types for all the new code files that you might generate and then as time passes you can come back and one by one go into the existing code files and transition them to use nullable reference types but as we imagine that would be a process that would require a little bit of time so it's not something that you would probably do overnight wrap this up I would like to say that the quantifiable end result of using nullable reference types is actually huge that would make our applications much more predictable and in the end much better than previously however as we have seen there also are a lot of challenges headaches and pain points that we might face down the road when we want to be fully knowledgeable reference types compliant like when we're using Entity framework core or dtos or razor pages but there might be also other scenarios but overall I think that knowledgeable reference types have a terrible developer experience but they come with a great and valuable end result it's in the end up to you to actually weigh in on all these different options and then Define for yourself if nullable reference types make sense for you in your or in the context of your specific project because those or these kind of decisions is something that we will always have to make in a certain context that might influence our decision in the end this being said Thank you really very much for watching if you have enjoyed this video don't forget to hit the thumbs up button so you help others to discover this video easier also if you didn't subscribe to this Channel please do please hit the Subscribe button and also the notification Bell so that you are notified whenever we have something new happening on this channel and if you have any type of question or you just want to get in touch with me don't be shy and hit head over to the comment section of this video and just leave me a comment and I would be more than happy to get in touch with you this being said once again thank you very much for watching and until the next time I wish you the very best
Info
Channel: Codewrinkles
Views: 2,574
Rating: undefined out of 5
Keywords: nullable reference types, nullable reference types dotnet, nullable reference types .net, nullable reference types c#, dotnet nullable reference types, .net nullable reference types, c# nullable reference types
Id: KlqV9YBtiLI
Channel Id: undefined
Length: 26min 23sec (1583 seconds)
Published: Sun Feb 19 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.