YTread Logo
YTread Logo

Change your habits: Modern techniques for modern C# - Bill Wagner

Jun 09, 2021
Good afternoon, I'm Bill Wagner and this Twitter handle is on the slide so you can contact me later however you want. It's also my GitHub handle, so if you have any other questions, go to the C Sharp Docs repository and you can ask questions. and ask questions there, so I chose the title of this quite deliberately, so that's what I want to happen in this talk, so I'm going to show you a variety of different things that you can do with the new features that we have. I've added to the c-sharp language which should make you more productive and should increase the quality and clarity of the code you write, so what that means is that when I start each of the demos I show code that looks like that.
change your habits modern techniques for modern c   bill wagner
It could have been written a few years ago. I don't want you to come back and leave, oh no, I have to rewrite all of this because the codes have probably been tested, it certainly works, it's certainly in a good place, but as we've been. As for the language, we wanted to improve it a little bit, so the idea behind it is that if you think about programming languages, they are all opinionated, they were designed by people who thought that certain things, certain

techniques

and certain goals were important, other things not so much. a lot of it is like that at the time of its design in every instance they come up with ideas that say we think this is the way software should be written and this is how it should be done and they made those things easy, but if you look at the arc of Computer programming languages ​​usually take a long time to get a lot of adoption and once they have a lot of adoption, it takes them a long time to stay in the industry because there is a lot of code out there that uses that language, so every El programming language expresses opinions in many ways.
change your habits modern techniques for modern c   bill wagner

More Interesting Facts About,

change your habits modern techniques for modern c bill wagner...

Programming languages ​​will have intentional opinions. We think this is a good way to solve these types of problems. Some languages ​​and probably all languages ​​in one way or another have negative opinions. I know we don't think. about that and now it's here, I mean, every language does it, so I'm not going to try to pick on any one in particular. Here language expresses opinions by making some things easier and others more difficult, and this is what we are really doing. What we are fighting and trying to do is continue to evolve the C-Sharp language. If you look at the arc of our most recent

modern

language releases, we've learned a lot in the industry since C-Sharp's initial design in 1999-2000, so we want to make it easier to create better software using the

techniques

that people generally recommend in 2020 and beyond, that's the only way the language will remain relevant;
change your habits modern techniques for modern c   bill wagner
It will still be an object-oriented language, which is where its roots are. We're not looking to eliminate any features because that would be unwise, there's too much code out there, but we've also recognized and continue to recognize that things that we might have thought were good ideas or we might have thought now this is pretty easy. 99 or 2000 is not easy anymore, so we want to improve it and we are doing a lot of things to make it easier to work with different types of data. One of the things we learned, you know, if I look at the arc of history in computer languages, the arrival of Java and c-sharp was because the industry finally realized after C and C++ and other similar languages ​​that managing allocated memory was much harder than anyone thought.
change your habits modern techniques for modern c   bill wagner
Could it be correct how many different errors there were due to C++ knowing and deleting and different types of new and deleted elements etc, smart pointers etc. Better yet, it's a problem, wait until you see it neat in Java, these things are easier, but now when you look, there are still things that we didn't make as easy as we could from things that we have now learned as an industry with the types of programs that we write now, so it's important to start adding those features, so with that introduction, I'll really spend the rest of the time looking at the code and talking about the way we wrote things and the recommendations we had and how we would do that now and the different things that we've added to the language that we want you to explore and start adopting

habits

every time you work, so the first thing we're going to learn is that if you work in the area of ​​computer languages, the only demonstrations you can do involve dots and an in-person class. because they are easy to explain, I don't have to explain the domain, we know what a 2D point looks like, we know what a person object should be like and points allow us to work with value types in a very nice and simple way, and person objects allow us they allow you to work with reference types, so I'll start with a few things in our basic points class.
I'm going to scale this down a bit. After switching, I have x and y. I can publicly assemble a private configurator. I know that I can. simplify some of this and I'll come up with a good amount. I have a design decision that I want to calculate the distance, but I want to calculate it lazily, so I have a nullable double to store the distance and I have a property that retrieves the distance and calculates it if necessary. I have a constructor. I have the same operator. Non-equal operator. So I have to override equals and we have a Gitch hash code that I'm not going to use.
Debate whether it's a good hash code to get or not, but it keeps the compiler happy and then, just because I want to make sure it's good for beginners, I'm going to show you a little trick to help you get through that entry-level programming interview where everything the world says I want you to swap these values, and you know anyone has their first programming interview, it's like x equals y y equals x oh, you were wrong, you've never had to rewrite that code, but just in case you do. I'm going to show you a cool trick, for example, a C sharp 7 and we added tuples and we added them just so it was an easy way to not have to write a class or a struct every time you wanted to hold more than one value. right, because that was an encouraging behavior that we didn't like, right, we want to keep these things together, but then I had to write a class, I had to put all these things in there, I'm going to define these methods and now suddenly I have two. pages of code just for something that might make a lot of sense, so we put in tuples.
Once you have them, there are some really fun tricks you can do, so let's start here with this builder. It sounds like you'd write a lot of constructors. for any of the types that you create, I have a set of private fields, I have a set of arguments that come in and I will set each private sentiment to that argument and depending on how many fields you have, you will get this different life this is this this is that that is the other thing well, let's write this in a really simple way now that I have two groups and I'm going to go is going to be equal to right let's create another tuple that has the arguments I want to pass to it, okay this is one of the ones we don't have code fixes or refactoring and there are a couple of reasons for that, this looks good because it has a total of three variables and usually They are small in practice when I write code and when I look at different things I will use this technique almost all the time with two arguments.
I often use it with three, depending on the length of the variable names. Four is starting to sound silly so I usually don't do that and then it would go back to separate statements, so if we were going to add a refactoring for this and there is a possible community project called to do it, we would like to be able to do it both ways so we could say take these separate statements and convert them into a tuple task take this tuple task do Split it back into separate statements because classes have a way of growing fields occasionally over time, so there's that one, as soon as you see it, you start looking at something and you go to this equal equal operator, it looks like it should do something a lot. so and if you've ever done code reviews, you may often see, depending on the thoroughness of

your

testing, that sometimes in one of these you may miss a left and a right or you may miss property names because we copy and we paste this.
Okay, because that's what we do, so let's write it in a way that makes it a little bit easier, so I'm going to go left no I don't need that extra and there I don't have to make sure I understand the correct logic. It's just this tuple on the left that I quickly create. The tuple on the right quickly believes that life is good and we can do the same. of course with not equal and then because people copy and paste the code you know that at least somewhere in

your

code base instead of or there is a y and the logic is wrong and here I can just leave out X leave out Y and it just shouldn't be the same, right, that comma with tuples, of which we will have a few more.
While we continue to go over some other core topics, I now said that we had this quartz ex

change

thing. I know what we're going to do now. That will be X comma y is equal to y comma. X takes that obnoxious interview person with your weird, stupid programming. you ask because that's going to work well, sitting with John Skeet, he showed me a version of this where he does the same kind of trick with the Fibonacci sequence and you know this current neck is cool, so we start doing things like that. because the way we defined this and said we had to do this for the language is that it will evaluate all the expressions on the right side to create that tuple and it will evaluate the expressions on the left side to find the variables in which those things are stored . and then do the homework to get this working properly and where we really needed that in practice, in addition to tricks like this, is to be able to show things like you could have expressions on either side and things on the right side could

change

what happens on on the left and we need to know exactly how it worked, yeah, that's cool, so that's the first part, which is just some little tricks of traveling with tuples whenever you look at a couple, maybe three, sometimes four variables that You want them to travel together.
Go ahead and put them in a tuple and use them in these tricks and again, none of these really do anything different than what we saw before with the code above. It's really visual, take a look and see if you like it. the way it looks for each individual class and individual struts that you're working with, you know if you write this and you have five or six things and it just looks bad or if you have some really long variable names and it looks bad and don't do it, but this is just something that provides more clarity on what you're right, go ahead and do just that, so now the next thing I really want to talk about is we added and this was one that was added in the seven point versions where We worked hard to make it better to write read-only structures and we've been saying to make value types immutable since c-sharp 1.0, that's it for you all.
I didn't really provide much support for that, so what we've done now is say I said in my design, you know, this really should have been an immutable structure. It stores these points, I don't want them to be modified once I've collected that data, they should never change, so now I can add the read-only modifier into the struct definition, so if I wanted this to be immutable, I would do that and now the compiler notices that I have red squiggles appearing everywhere. about the place here because I didn't make it an immutable type in the sense that any of the private member variables that the compiler now tells me must be read-only because they weren't, this wouldn't compile, also nothing I try to set any of those read-only variables, well those can't be, you know, that's bad: you said this was supposed to be a read-only structure, now the drive behind this was performance in certain areas that we now want to be able to approve. trucks by references we want to be able to do things like use span and reuse memory and if the compiler can enforce the fact that a structure does not change and cannot be mutated then it is safer because we can pass this structure by reference we know that it cannot be modify and it is safe when it returns or if you pass something by reference and it could possibly be modified, the compilers will make a copy to make sure the codes are correct, before doing so. this is completely read-only, this is where a lot of design decisions are made, maybe I don't want everything to be read-only, so let's write down what we can and say I know this method doesn'tmodifies the state, so you know. ok the get export should be read-only, so I can put the read-only modifier in there to ensure that the get accessor doesn't modify anything inside this object.
Okay, that may seem redundant, but it's actually not because of the property we know how to run. code so you can change the state there again, we'll do the same thing with the read-only mode on the Y and then here in the distance on the right that shouldn't change the state, he said, so we'll write the read-only modifier in that property is a quick thing to keep in mind if you only have a get accessor, you can't put the readonly modifier on the get accessor you have to put it on the property, ok, and if you notice as soon as I do it, I get an error and another warning saying yes, you can't do this because you said it was read-only, right? so saying it was read-only, you can't modify it and now you really have to make a design decision about what you want to do if you want to make this completely read-only or if you still want to allow it.
To continue this lazy evaluation, let's say that whenever I create a point in this particular application, I'm always going to calculate the distance well, so I would probably move that calculation to the constructor and actually make it read-only and cache it. value, let's say only 1 in 1000 points. I'll calculate the distance and then maybe I don't want to pay that cost and I'd say okay, I'm not going to make this read-only and then I'll take that into account because this goes In the set properties it doesn't give me a warning here it'll just say the same thing, so this is what we're trying to get at and what we want you to be able to do is anytime you're looking.
In a struct alone, this read-only modifier cannot be added to classes any time you are creating a struct. If your design was to make it an immutable struct, add the read-only modifier in the struct if it was intended to be read-only. some things - just then add it to those methods, so I'm going to wrap this up because I want to show one or two more techniques that we've added. I'm going to make this read-only and then we're going to deal with some of these errors, now I'm going to use an implicit property here and now I'm just going to say, well, this just has an access error and I'm going to use the syntax property readonly when you do this whether it's in a readonly structure or not the compiler knows the code it generates and it automatically makes that property readonly as a readonly modifier and so the CLI will know that that X The property is a read-only property, really read-only and it will do the same thing with Y and remove that.
I love deleting code and getting functions and now of course it will be read-only too. You could add the read-only modifier. here, if I wanted to, but it's redundant, it doesn't add anything, it's already there, so now I'm going to have to change the way I do the distance. I'm going to remove the nullable attribute and here I am. I'm going to do the same trick. I'm going to make this a get-only accessor. I'm going to get rid of everything that does this. You know, math, period, square root, x times X plus y times y. Okay, and again you can see. this gets a little bit longer and it should be a distance and they become uppercase because I need to use the properties right and now I have a truly read-only structure and now I have to delete it because that was done because of someone's mistake.
It was just any data backwards, so we needed it for a while, but now I don't really have a read-only structure. The point of this hack in the sense of what I mean is that this should enforce what your layout is, add these modifiers. to enforce the design you will communicate to other developers what you meant, someone comes here later and wants to add a method and I call the readonly modifier which was probably there for a reason, maybe I shouldn't add something in the mutated state , maybe you should do something to create a new point based on existing data, however I wanted to modify it so that you communicate that design to others and communicate it to the compiler.
The compiler will now help you enforce your design. Okay, now a little. As for our next trick, what we're going to do is the other big feature we added in c-sharp eight: recognizable reference types, and once you get to dotnet core 3.1, more and more base class libraries have been annotated. so the APIs now have noble annotations, so for example, I don't have bubbles turned on here and if I have a method that looks like this, now a green squiggle appears warning that what that tells me is that as of dotnet core 3.1, the equals override has now been annotated with object could be null, so it's an object question mark, okay, so I have to say it, okay, this is one of the reasons why officially c-sharp eight is not supported by older frameworks, while the nullable reference types feature on the one hand is great and is fully implemented by the compiler, so the compiler would do the right thing.
Older libraries have not been annotated, which causes two negative effects. You'll get warnings at times you shouldn't and you won't get warnings at some of the times you should, so it doesn't really help that much and it would really provide a sort of false sense of security if you add this to your code and expect everything to be fine. good, but you don't get it. annotations of the libraries you use from now until net five and then net six, we will continue to add more annotations on more dotnet libraries based on how many, depending on the usage and download statistics we have, for which classes and which API is the one The more it is used, it is a bit of work to write everything down, so from now on five nine and six as you start adopting c-sharp eight and nullable reference types with each new version you may start to see some new warnings because more APIs have been annotated, but that should point out potential bugs in your code, so we still want to encourage you to start looking at it and start considering annotating your own code and activating it where you can.
I'm going to continue as we talk about this and start adding this. Here's something we've learned over time. Nullable reference makes the null reference exception the most reported exception in any dotnet application anywhere on the planet. It's more than double any other type of exception we've seen in any telemetry we see when looking at open source projects on github. Null checking is the most important expression and work that people do in code, so let's do our best to achieve it. more efficient so you can add null checks without muddying up the rest of your algorithms and I'm going to admit that I'm totally guilty of this because I work a lot in Docs and write samples and we often don't check for nulls because the more null checks we add the harder it will be to discover the algorithm that we are trying to explain, so instead of writing the code that you would actually have to write in production, we cut out some of these and we want to change that habit ourselves and by doing this we are going to do some things to add things to the language to make null checks not require as many lines of code, so let's look at our equals override, right now it's at about ten lines of code, there's actually only one line of code here that has anything to do with the algorithm and that is the one that calls our equals operator that says this is value-based equality, check if all the properties are equal.
Great, the rest is related to null checking, that's bad, so let's try to reduce this a little bit, so let's do this and say okay, then if the object is the other point, we'll add some things with pattern matching. so I'm just going to clarify that here and then okay now I'm just going to return this is the same as I still need the support sorry I don't want to go into that error and now I have it okay so now I have it. reduced a little. I feel a little better. It's a little clearer to see what you want.
Well, now it depends on whether you like the ternary operator or not, but I can turn it into a single one. line expression and I can return is a period, another question mark PT, boom, yeah, if not, just return false, okay, and normally I would try to format that like this, okay, so now we have a very concise null check here if the object is a point type if you have been a c-sharp program for a long time, you knew that for a long time it only worked with reference types, not with value types, it works with value types and now we can say that it is and has an assignment in the same statement and then we'll just check for equality if the test was successful, if not and if it was null, it's not a point, so the is operator only returns true if the object is not null, either a reference type or a value type, in total. always returns false because it's not an object, that's not cool at all, so let's go to a slightly simplified way of doing null checks, but to actually do null checks, remember I said I do person or point classes, so yeah, now Let's go over the type of person I have some reference properties and we have the same type of thing here.
What I have is that I have a person with a first and last name and we know that more than half of this code is the null track. Everything is fine, fortunately if you look closely you will see three dots on the launch because this is something that we wanted to start encouraging and we say use a launch expression, what does that mean? It's not right, so now if you look at what this does. I'm going to add a carriage return here to make this a little easier and I'm also going to change this to the body members expression because you know the square brackets are taking up space for no apparent reason and now I have a set that says "all good" so first the name is equal to the value and then a double question mark, just a null coalescent operator and if the value turns out to be null, then add your argument, no exception, okay, so I like it, I also like the way which Intellisense did for me, another little trick here, which is my only one.
The biggest complaint about API consistency in libraries.net is the null argument exception, the parameter name is first and the message is next in the argument exception, they are reversed. Thank you very much, in all cases, if you look at our documents, what we try to do. What we do is we try to use name parameters although we often put them in the normal order and then to make sure the refactoring works we use the operator name for the parameter name just because if I refactor this and change the name of the argument that the code will also be refactored so that we can do the same here in the next.
I have the same kind of thing. Turn on our light bulb and use the throw expression. Hey, I can do it here and in my constructor. Now I feel really good about this, yes, I can do the same thing there and if you notice I did all the null checks first and then the assignments and this refactoring knows enough to start moving them around and seeing them anywhere in a method, like this which with most methods you would write, you do something like: I'm going to try all the arguments first and then I'll go ahead and do more things later on the next one that I want to see.
Here we add a method to this person class to hyphenate a partner's last name so we can do a point - 8b or depending on how the partners would like to change like a DB point - a day and get a new last name that has the concatenation of those and you can see that I have to check if the partner is null and if it is not in all, I will do this job to set the last name and if it is now, I will throw a null VAR argument exception. Now I wrote this in a slightly different way because I wanted to show something very important about the way warnings are generated.
My brand said earlier in this project. I have enabled nullable reference types and I have all warnings enabled, so if you look at this argument, this person argument should be and it is declared as a non-recognizable reference type, okay, so if I remove this null check and I just wanted to leave the null track, okay, I don't get any warning, no error or warning. Say you could be dereferencing something that is null here, this is not good because I declare it non-nullable and then I put the trax back to null and I'm going to point that out with your code when the compiler looks at something you've annotated with reference types. nulls, pay attention to what you're doing and do a thorough static analysis of your code and what you've already written, so this partner is a non-nullable reference type, but down here, if I make a console . dot, write line and could do mate dot last name, well, there it is.
Now I have a warning under companion, the green squiggles, which is a reference warning that acceptsplay with us and the more I start to use it. I find myself going. I really want to use this tool very often. Well, as we get closer to the end, I'll end with a very small test. I don't want anyone to talk about this, but I'm going to write a routine and this routine will have an error and when you catch the error I want you to raise your hand, so now this told people that the entrepreneurs came back and said okay, This system is working, but we want to reward people who are very habitual and follow things, so we are going to allow people to get a one-year subscription and pay in advance thanks to the cash up front.
We like that and then you know they can be like that. frequent controllers and do something better, so I will create a public static method that will return a datetime for the start and an AJ time for the end and the method will be called generate subscription and what it will do well is that I need to find out that the start will be today, until now, a start is equal to date, time, period, now, period, date and you know it's going to expire in a year, so I'm going to do var and it's equal to a new datetime. to make the starting point year plus a starting month because it's the same day, I start right on that day, okay, okay, I'm seeing tragically few hands go up, so to make sure everyone can see the code , I'm going to jump here.
It's a bug that will appear a month from yesterday, there aren't enough hands on it, it was a good hit, okay, so everyone has it, what's this going to do, that's going to be really bad, someone raise your head hand very early, well, February 29, 2020, this is going to fail because there is no February 29, 2021. Now the point of this little quiz is that date and time math is really difficult because this is probably the most obvious example and I did it here today because it is very timely. a better way to do this while keeping this pretty simple is to start dot add years one okay because dotnet Franco and I need to add return start and the reason why I did that is now the datetime structure and any good day.
The library is going to handle all kinds of conditions, whether it's a jump here, whether it's yours, it ends in double zero, which you would think are leap years, but it doesn't go on and out of daylight saving time, if you're doing math at hours and hours. so on, if you're doing very extensive things about culture, john skeets, no. I'm an open source library that is incredibly powerful and does a lot more for a lot of reasonable things are built into a datetime, but they did this in particular because I would actually look at your code a little bit and maybe do a quick search to see if you're doing your own date and time calculations and I would try to replace it with something that's probably been tested so that's the code as we get closer so new

habits

are the reason we go through all this stuff and the reason why which I did some of this in a bit of a lighthearted way but focusing on a few different areas that it was fun to do. tuples every time you come across, I carry a few bits of data and I really don't want to do all the work to get a structure to think about using tuples.
There's also a proposal we're working on for records that would be a very, very short and better simpler syntax actually creates a type if you need it read-only members and read-only struct declares your intent when you write structs and value types and let the compiler apply it and communicate it to both compilers and for everyone who is going to read and maintain your code it has a better chance of being correct in the long run, the examples I was showing where I was doing the question mark, the initializations of the question mark and other things like that, the technique we are referring to as it is. natin everything by initialization, so the more often you can make sure that a field, an argument, or a variable is initialized to something that is not null as soon as you declare it and create it at that point in the text, you know that variable It is never null. and you can declare it as a non-null reference type and the compiler will help you catch those errors.
Remember that they are only in metadata, especially in public APIs, especially because you are in this process where you are probably migrating some code. and some of this hasn't been noted, check for null values ​​anyway and especially in public APIs. Like I said, whatever we're doing, we're annotating APIs. I can guarantee you that we won't delete null chat patterns and data every time you want. turn things on and do a lot of if-then-else some kind of logic looking at a property looking at a type consider pattern matching it's a different way of thinking about a problem but it's a very powerful way for certain classes of the problem, this It doesn't mean stop using object orientation, stop using inheritance, I would never want to say that, but if you look at the algorithms that I wrote, I didn't really have an inheritance hierarchy to work with, but it's been really cumbersome to create. one where the switch expression was actually much more powerful and much clearer in a smaller space for exactly what the code was doing, that's what we were looking for and then the classic one because it really reminds you of date math and time and what I would do.
The recommendation here is to do what you can to follow the good software engineering practices you are doing for your applications. I'm sure everyone is building some kind of culture to try to write good software when they find that cumbersome. Do some research to see if there is a better way to follow good practices without writing so much extra code, specifically look for some new features and recommendations. I used the light bulb today and there's also a screwdriver icon for other recommendations with a purpose if If you're using Visual Studio, you'll get suggestions for some of the things we think we've added, features you may not know about.
Check the screwdriver bulb and I mean this about talking about looking for the new research. and we did a little research, we love Stack Overflow and we love that it also helps me every day, but very often now what we find, because dotnet has been around for about twenty years, is that there are answers that have 15 years of uploads and were great. perfect answers for a long time and we've added features so that yes this works but you know there's a better way to do it and the best way has maybe six months of upvotes so it's harder to find and as I was saying Tessa.
In your keynote yesterday, it's a positive feedback loop that people keep seeing that first answer and using it even though there may be a better way, so when I say do a little research, take a little more time, including Stack Overflow, we're trying really hard. to stay up to date on Docs and check the IDE recommendations to try to find some slightly better things and use the things we're adding to create some new habits. You could add ms /new c-sharp is where that will point to the latest c-sharp stuff. I'm going to mention in particular two things that I put here if you go into the sample browser, which is Doc's, those Microsoft communication slash samples and search for Explorer c-sharp. check out any of the things we have that will help you explore some new things and new areas that one day I will show you.
Another thing we're doing is we've started adding a dotnet Docs what's new page so every month we'll be posting you know what's really important and new and as a bonus because we're all open source we recognize to everyone who contributed to Doc's in the last month by their github IDs and if they added their name to the github profile, we will do so. Put it in there, but we don't go any deeper than that and if you look at our tutorials, the toll calculator is part of a much larger app on pattern matching that will take you through a lot more techniques that you can use there, thank you.
For your time. I'm sure everyone is excited to get to the front desk, but I'll be here for any questions. You can ask me questions now. I think we have a couple of minutes left. Thank you very much for your time.

If you have any copyright issue, please Contact