Check out a free preview of the full C# and .NET Basics course
The "Generics" Lesson is part of the full, C# and .NET Basics course featured in this preview video. Here's what you'd learn in this lesson:
Spencer introduces the concept of generics and explains that they are a way of implementing polymorphism. Examples and explanations of how to create generic classes and methods, as well as how to constrain the type of a generic are provided.
Transcript from the "Generics" Lesson
[00:00:00]
>> Spencer Schneidenbach: Let's talk about generics, which is a advanced language feature for sure, which is one of the things that I really wish was in the original.net runtime, but it didn't make its way in, because you have to ship obviously. And they basically allow you to provide to define different things in different ways, and it's a good way of implement, it's C sharps main way of implementing polymorphism or different forms for things inside of the language.
[00:00:32]
So this is the syntax for what's called a generic type. And you can see that it looks kind of funky, it's like, where did the angular come in, why are we writing react in our, in a C sharp code, but it is a open. It is a alligator mouth open a greater than sign, or, I guess that's the less and sign, the name of the type and the the closing bracket, the closing angle bracket.
[00:00:55]
And what this can do is it allows us to define to find types that do, kind of different things based on the type that we give it. Let me show you what that looks like. Let's clear out all this other stuff boom, let's put that in. So what we've defined is a very simple, very contrived example.
[00:01:11]
Again, not real code that I would write, but good for illustrating this language feature. Let me break this down for you a little bit. This is said to be a class called box of T. Now, T can be named anything. Are all types that are, what are called generic arguments.
[00:01:31]
This is a generic argument, aways are denoted with a T first. Let's call it T item, kind of just to set it home. And you notice that, when we hover over T item, it doesn't really tell us what it is. It just says T item and box, T item.
[00:01:47]
Well, that seems kind of circular, what does that mean? Let me show you. So let's say that I wanted to, something that I wanted to box up a string, box of a string. I can instantiate this object, right? And I can give it a type called string. So give it the type argument, open and close parentheses to finish calling the constructor.
[00:02:12]
What are the implications of this, why is this useful? Well, the implications of it are that we now have methods on this instance, where the only thing that we can do is get an item of that type and set an item of that type, so let me show you.
[00:02:27]
So box of a string called setitem, and we open a parentheses and we look, we see that string item is the type of the thing. Now that's weird because it's T item, what's T item? Well, we've defined the type by providing it in this type argument here. So we can set this item to an instance of a string.
[00:02:50]
And then of course we can,
>> Spencer Schneidenbach: Print a line, box of string, and get item to get the copy of the item. And you can see that our ASDF string is printed right here. Seems weird on its face, but it's very useful because now we can do certain things like restrict behaviors.
[00:03:17]
Now I'm all about safety, I'm all about restricting behavior where it makes sense. So, box of a string.setitem, the moment I try to put anything in there that's not a string, it gives me a compiler. It says cannot convert from int to string because it's expecting a string to this box object because that's what we've specified that this is a box of a string.
[00:03:36]
Correspondingly, we can also declare box of an int. New box of that's how you say that an int and box of an int has the same properties as box of a string in that you cannot set it to something that is not the target type, which in this case is int.
[00:03:53]
So extremely handy, especially as you get down into, like I said, length. This is one of the foundational things that makes link work which we'll talk about here shortly. I'm gonna show you a couple of other properties of generics. This is how you create a generic class, we kinda already did that in our box example.
[00:04:12]
You can also create a generically typed method so you can have a method on a class that is not a generic class, but that is a generic method. And what you can do is use that, let me copy paste this code in.
>> Spencer Schneidenbach: Delete that, put this in here.
[00:04:36]
And this one's a really silly, let's call this a static class, because it's kind of doesn't do anything static here, because it doesn't do anything, and we can define a method on it called Get default value, where we pass in a type. So we know that, based on the fact that it's returning the default value, that the default value could be for into, could be zero for a reference type, like person it would be null.
[00:05:01]
So what we can do is we can say var default value of int and then we can say utilities do get default value pass in the int that it is. And because we've defined the generic type here as our return type for our method. We're gonna go down here and we're going to see that we get an int out of that.
[00:05:23]
Really cool, really neat, really a ton of flexibility. It looks strange, just wait, best is yet to come. I'm gonna show you a few more things, just about generics. We're not gonna go over them in the code, but I do want you to make you aware because they are important to know.
[00:05:38]
So you can basically constrain a type of a generic to be a specific thing where you can say that I want this type of tea. The only types that can go in there can be class and eye disposable. So int, for instance, would not fulfill the requirements of this generic type.
[00:05:57]
It's called a type restriction or type constraint. And it's supremely useful because what you can do then is you can now know that when this T item is passed into this manage method, we know that it's a reference type. And we also know the behaviors and properties that it gets from the interface that we've set.
[00:06:17]
It has to be an I disposable interface, it has to implement that interface.
>> Spencer Schneidenbach: Same thing here you can see that in this Data Manager class, this contrived example that we've constrained the type that T has to be a class and it has to be an I track entity.
[00:06:38]
And And you can see that i tracked entity has an id guid property, and thus we can access that item's id property because we know of its type ahead of time. So, pretty useful, multiple type generics so generics can have multiple type parameters I think the language limit is 16, but I've never gone higher than two or three, I think.
[00:07:01]
I don't even know if I've gone as high as three, but one and two are pretty common for me to declare. You'll see that when we look at the dictionary data structure, this will become super, this will become important as we talk about that. So the thing that we're gonna talk about, especially in the ASP.NET Core class, the thing that I see a lot is this idea of a repository.
[00:07:23]
So I don't talk in software patterns a lot, because I feel like, especially for newer programmers, that we could talk about software patterns all day, but they're little too abstract sometimes to really know what they mean. But there are some software patterns that are really important to know and understand.
[00:07:37]
One of them is the repository, pattern, okay, basically a way of a common way of defining how you would get a thing in and out of a database, and how would you get all of them, and how would you get some of them, and so on and so forth.
[00:07:52]
It's a repository, it's literally an abstraction for most commonly used when talking to a database system. And so if you have this repository here, where you have this interface defined, and you basically say, wait, I wanna define a repository, the T, the type argument here will always be class.
[00:08:14]
I wanna be able to define a repository where I get all of the things that are T, or I get them all by id, or I get them, or I wanna add them, or I wanna delete that particular thing. This gets really powerful when you start talking about different repositories for different types of objects.
[00:08:29]
In the real world, in the database, you don't store customers next to products in a table. You might, for some weird reason, but in most database and software design, you probably are going to put those things in separate database tables or even separate spreadsheets, wherever they're, wherever their final resting place may be, wherever their source of truth is.
[00:08:48]
They're probably going to be in different places. So it's useful to be able to go in and say, I want to get a repository for my customers, and I wanna get a repository for my products. But I wanna keep those I want to treat those as separate things, and then I want to operate on those objects as if they're separate things.
[00:09:05]
That's the power of generics, that's why generics are important. And as we get down further into this, you'll see like how important they become, they are very useful. Any questions?
>> Speaker 1: Is there a generic concept where we can say something like T should have a foo method or a bar method, both will be fine?
[00:09:30]
>> Spencer Schneidenbach: No, the type system in C-sharp simply isn't that flexible. And usually you constrain it down to an interface at the lowest level. TypeScript does have that, but as far as its generics, type system goes, but C sharp does not good question.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops