n important feature of the C# language is Generics. Generics are not necessarily new. They have actually been out since C# 2. They provide a way to make it a lot easier to work with code, but also to make your code more efficient, and definitely catch errors up front as you’re writing the code.
In this particular demonstration, I’m going to walk through some just fundamentals of what C# Generics are and how you can use them in applications.
To start, I have a little bit of code here already ready to go. You can see that I have a car class,
This car class has an ID, and it has a make property. Now, we can certainly add others, such as make, model, year, things like that. But we’re just going to go with two simple ones.
[0:48] What I have here in my program is, we’re going to new up our car. Then I’m going to use, this is a special type of initializer, called an object initializer.
This is going to assign the properties for ID and make, and then we’re going to use these.
[1:04] One way I could put these two Cars into a collection, is to actually use an Array. The problem with Arrays in C# is they’re fixed length. If you want to keep adding to that, you’d have to make new Arrays, and then copy back and forth between them. It’s a little bit problematic.
What I’m going to do instead is use a Generic. You’ll notice that we’ve already included System.Collections.Generic.
This is the default namespace for Generics in C#. If you’re new to them, this is one that’s actually added for you in the projects.
[1:36] What I’m going to do is create a List of Car like this:
We can definitely use the var then select a List of Car, like this.
Or, I’m actually a pretty big fan of the var, which basically lets the compiler figure out the data type on the fly. We’ll say Cars is new List of Car. That’s how I think of the Generic marker brackets <>.
[2:06] What a Generic is? It is a code template. What’s going to happen here is I want to create a List but a specific type. I could always create a List of Object. We could use the old ArrayList as an example. The problem with that is, when you add it, it gets what’s called “boxed”. Then, when you pull it out, you have to cast it from an Object or convert it back to a Car.
By doing a Generic, I get a strongly‑typed way to add it. In fact, you’ll see here, if I just do a new List and then say Cars., notice when I do add here that we can only add a Car.
[2:40] If I try to add an INT or a STRING or a BOOL or an Engine, or something else, it’s not going to work properly. That’s as it should be. That catches us as we compile, and it makes it so we don’t add stuff we shouldn’t be adding.
What I’m going to do is I’m going to use a little default Array, or Collection Initializer, you’ll hear it called. I’m going to create a List of Car and then do a { and end } and a semicolon (;)
[3:06] In here, I can actually just put my Cars and just list them. I could call Cars.Add > Cars.Add > Cars.Add etc… But this provides an easy way, since I already have the Cars, to add them into the Array.
We’ll do: Car1, Car2. Just to prove this works, let’s go ahead and do a quick foreach then tab tab, get a code snippet going.
We’ll say foreach Car in Cars. Let’s write out Car.Make. We should get Ford and Toyota written out.
Let’s go ahead and run it. You can see that indeed it works.
We get Ford and Toyota, and we’re ready to go.
[3:50] That’s one aspect of Generics. I’d argue that’s the aspect that you’ll probably use the most, just simply creating custom collections of a specific type. I prefer to go with List in many scenarios, where I just have a set of objects, and I want to add them into an Array structure, then we can use the List to do that.
Another aspect of Arrays is that you can actually control what types are added into a class. We did that here with the List. We said a Car can be added into the List, but now let’s make a custom Generic.
I have this Engine here, V8.
Let’s add a new property. I’m going to make a property we’ll call Engine.
I’ll just do a prop, tab, tab for the code snippet.
I’m going to have an unknown here.( I’ll come back to that.) I’m going to call this property Engine.
It’s not going to work as is because the Visual Studio IntelliSense is saying, “Whoa. What are you doing with the question mark?”
What do I want to put here? If I wanted to hard‑code V8, I could. We could come in and say V8.
The problem with that is now I’m locked into a V8.
[5:01] What if I want the user of my Car class to be able to supply the type of engine that they actually want to use? We could do that through Generics. What I’m going to do is put a little marker up here, and I’m going to name it <T>.
This is something that Microsoft does. It just basically stands for what’s the type that you would like the user to be able to add in for this Car.
What I’m going to do is replace V8 with the T.
What I’m saying is that, at this point, I don’t know what the type of Engine is. It’s a Generic template. If I were to supply, for <T> V8, then the compiler, at compile time, will come in and put a V8 right here.
[5:44] If I said it was a V6 for T, then it would put in a V6. The compiler will take care of that automatically. Now, we have a way to be really flexible.
I’m allowing people that use my Car to supply the type of the Engine that they actually want to work with, as opposed to me hard‑coding that type of Engine. It makes our applications more flexible and easier to maintain.
Let’s go ahead and use this now.
We can see that our V8 just has a Horsepower, down here.
What I’m going to do then is allow us to create a V8 and assign it, but I obviously have to supply what is the T, what’s the template marker, and what do I want to replace that with. Right now, I only have one Engine, V8. Imagine that I had several. Then we could go in, and use those others.
[6:37] Let’s come on back over to Program.cs and notice that Visual Studio now says, “Hey, I don’t really like what you’re doing here with Car.”
The reason is it doesn’t know the type of Engine. You’ll even see in the IntelliSense there, that it says, “1 type arguments” parameter is required.
[6:53] What I’m going to do is say I want a Car1 of a V8 Engine. Then, down here, I’ll say I want a Car2 of a V8 Engine.
Going with the same concept here, we could say Engine = new V8.
Now, I’m able to add in a specific type of Car of V8. If I were to, here in the Engine, do V6, let’s see what happens, even though I don’t have a V6.
That’s going to error out, and our Car is now also going to error out.
[7:37] It’s not going to allow that to be passed, because we’re now saying that you have to pass a V8, but yet I tried to pass a V6. Even if I had a V6, it wouldn’t take it, and it wouldn’t compile because we told it was a V8. It makes it really nice to catch errors and issues up front, as opposed to, say, at runtime.
You’ll notice that this looks good. We’re ready to go with our custom Generic, but with the List, it’s choking. If we mouse over it, it says it requires one type parameter.
I need to say that the Car is a Car of V8 Engine.
[8:17] We can add a new List of Car. For the Car, I have to say what the T is because, again, look back at Cars.cs, we said there was a T.
I’m saying what the T is. It’s a V8, and it takes it. If we run it, we’re not going to see much different than when we initially ran it.
Let’s go ahead and iterate through as we write out the Car.
[8:42] I’m also going to include (car.Engine) and I’m going to write out just the (.ToString).
You can see that we do indeed have a V8 for the Ford and a V8 for the Toyota.
Comments
Post a Comment