 One major thing that C sharp added on top of the baseline of Java is that C sharp has what are called structs Which are these things that are very much like classes, but for two differences first off They're value types rather than reference types and they cannot use inheritance So you can't have a struct inherit from some other struct or class or anything So the fact that they're struck types what that means is that here where we have struct cat rather than class cat If I create a variable C of type cat this variable stores a cat value directly All the data elements that make up a cat That's this one piece of data in memory and C is not going to store a reference It's going to store an actual cat value directly And so here we create values of struct types just like we create instances of classes But when we assign a struct value to a variable or pass it as an argument into a method or set it as the value of a field In all those cases the value itself is being copied not any reference So here the cat value created by this operator is being copied in whole to variable C Here we're setting the age to five and if we create another cat variable C2 and assign it the value of C Well, we're copying the value of C to C2 and we now have two separate copies C and C2 are holding separate copies of Separate cats they're not storing separate copies of the same reference they're storing actually separate cats And so immediately after this assignment we can retrieve the value of age of C2 And it's the value five because C2 and C after the assignment all their fields have the same values But then if we set age of C2 to 9 that is affecting age of C2 Not C if we immediately after get the age of C We'd still just get five because this set here only affected the cat value stored in C2 Not the cat value stored in C Again C and C2 are directly storing totally separate cats So that is the distinction between reference types and value types Question is why do you ever want to use struck types rather than class types? Well, there are cases where dealing with values through references Incurs significant overhead because every time we read and write data through references That's two memory lookups rather than just one So actually there are trade-offs if we had a very large struct with many fields Then you'd have this thing that takes up many bytes potentially and so every time you did an assignment or Passed it into a method or return destruct out of a method well Then that means copying a significant number of bytes whereas if you're dealing with these references then references are always the same size No matter what they reference and so when dealing with large data types It's often more efficient to pass around references to those large pieces of data rather than copy the things in full So there's really no definitive rule about when to use classes and structs in general though Structs are used for smaller pieces of data and classes are used for everything else Classes sort of the default and for certain cases where you know would be more efficient You might decide to use a struct instead a very common practice is to give classes getter and setter methods These are methods which get and set the values of the fields such that users of the class should call these methods Rather than getting and setting the fields directly Here for example rather than having users of this cat class directly access the age field through get and set We've created a get age and set age method get age just returns the value of the field and set age has an in-parameter Which is what we set the age field to be So else we're in code say we have this cat C Rather than using the set and get operators. I call set age and get age and it has the same effect What is the point of doing this? Why not just use get and set? Well, it's a debatable point of style The argument is made is that by adding this level of indirection We then have more control over what happens when the field of our class is accessed because maybe right now Yes, when they get the age they just get the value from the field verbatim but what if say you wanted to add logic to your code where Every time the age is accessed we lie about the age So then we would have something that looks like this instead of returning the age verbatim We get the age from the field but then subtract two so then down here. We should see printed out six rather than eight This is a highly artificial example, of course, but I think it gets across the idea If the user of a class always goes through these getter and setter methods Then down the line we can intercede what happens when that field is accessed by modifying the code in these methods Because getters and setters are so common C sharp has what are called properties which get us the very same effect So here same code except now instead of those getter and setter methods We have this property called age of type string and because we can't have a name collision between our properties and fields We change the actual age field to be called age field rather than just age And the property has a get method which implicitly always just returns a value of this type and takes no inputs and a setter method which returns nothing and takes a value of this type and Implicitly that input parameter is called value. There's a special word value inside your setter which refers to the value which is being set So logically we have this property with the same getter and setter logic But as you see here when we use the property we do so using get and set operations When I set property age of C, it's not necessarily just a simple assignment to the field though in this case I'll still is this taking the value and setting the field, but it could do other stuff We could put whatever logic we want in here Likewise when I get property age of C, it's not just directly accessing the field. It's performing this logic So the idea of properties is that you end up with getter and setter methods That are a little less verbose to create number one and these methods are invoked by doing an ordinary get and set Properties probably seem quite pointless in the context of this C sharp pigeon language But an actual C sharp in the actual notation the syntax It is quite a bit less verbose when we create properties rather than creating getter and setter methods An array is like a list, but it's fixed in size and it also has a fixed type So say I can create an array of integers and when I create that array I have to specify how many elements It's going to hold whether five ten fifty a hundred whatever Here in this first line of code we're creating a variable nums, which is an array of integers That's what this notation means A stands for array and in the angle brackets we specify what kind of array we're talking about in this case we want nums to store an array of integers and Understand that arrays are reference types. So really what this is going to store is not directly store an array of integers It's going to store a reference to an array of integers To actually create an array of integers. We use the new operator Specifying we're creating here an array of integers and we specify the size in this case five So this creates a new array of five integers and this operation returns the reference to that new array Which is then stored in nums and then the Len operator here as in length operator is telling us the length of the array in this case five Next we create another array of integers But this is an array of three integers rather than five and we're signing that to nums So previously nums was referencing this array of five integers But now that's being overwritten and now nums references this array of three integers a separate smaller array And so now if we do Len nums we get back three So understand that arrays come in particular types like say array of integers or arrays of strings or arrays of cats or whatever's But the actual array values the instances you might call them those also have a type, but they have a fixed size So as far as the compiler is concerned the type here is array of integers But then the actual values of that type come in different sizes And so we can assign to nums here arrays of different sizes as long as the arrays of the correct type What's not valid is if here if I were creating an array of strings rather than integers Well, the compiler will be unhappy with this line because nums is expecting an array of integers not strings And so this is an invalid assignment Anyway, I'll put that back make an array of integers and that's fine And then once we have our array we can then set and get the elements of the array So here we're setting to index zero of this nums array We're setting the value there to be 89 and then down here We don't actually do this line Let me get rid of that when we use the get operator on our array We specify the index of which value we want to retrieve and now having set index zero to be 89 if we retrieve that We get the end value 89 Get nums one gets us zero because when you create an array all the values start out with their default for that type And for integers as you would expect the default value is zero for floats It's zero point zero for Booleans. It's false and for reference types It's null. So like say if I had an array of strings then initially all of the values are null Anyway, so if I get nums two that also gives us zero because it hasn't been changed from its default value And if I get nums three well, that's out of bounds our array only has three elements Indexes zero one and two three is outside that bounds. So this is a runtime error Again, the compiler never presumes to know what the value of any variable is and so it doesn't know what the length of nums is It doesn't know if it's an array of three inch or 10 or a thousand or a million Whatever it doesn't know and so it doesn't catch this error at compile time only at runtime when this operation actually runs Does it say oh that index isn't valid and then it throws an out of bounds exception Now here, let's assume that once again We have a class called reptile and a class called snake which inherits from reptile And so here if we create an array of reptiles size three and assign that to variable r Which is a reference of type array of reptiles Well, then we can set to index zero of r the first index we can set it of course to be a new reptile instance So this is creating a new reptile and storing its address in the first index of this array of reptiles Here we're setting index one of the same array to be the same value stored in index zero So now effectively the first two indexes of the array are referencing this same reptile that we created here and Then lastly we're setting index two to be a snake And this is valid because as far as the compiler is concerned snakes are reptiles any place a reptile is expected We can have a snake instead because snake inherits from reptile So this creates a new instance of the snake class and stores the reference to it in index two of this array However, be clear that the compiler considers r to be an array of reptiles It doesn't presume to know what the actual value stored in the array r So it doesn't know that this particular index is actually a snake and not a reptile So down here when we get r2 a get operation on r is always as far as the compiler is concerned Going to return the value of type reptile We know at runtime it's actually going to be a snake in this case But the compiler doesn't know and so it doesn't like this assignment We can't assign a value retrieved from this array of reptiles to the snake variable We can though of course perform a cast as far as the compiler is concerned this operation returns a reptile But then we're casting to snake and asserting well at runtime It's actually going to be a snake the compiler is now happy and at runtime This cast operation is doing a check of hey wait. Are you really actually a snake? If not, I'm going to throw an exception otherwise it returns the snake instance So this is just like what we saw with variables if I have a reptile variable storing a snake The compiler doesn't presume to know that it's a snake We have to do a cast to get the snake instance stored in a reptile reference and here for the elements of arrays It's the same deal If you're wondering whether C sharp has lists and maps the answer is yes along with many other collection types But they are not considered to be built-in features of the language instead They are just classes of the standard library the C sharp standard library comes with many classes for various functionality Including lists maps and other collections, but we won't get into that here Instead we'll get into that when we look at the real actual C sharp language One more thing to discuss before getting into actual C sharp is what are called generics here We have this class Alice, which is a generic class as Distinguished by these angle brackets inside angle brackets We have these two type parameters Bob and Carol which within the class will stand in effectively for types to be supplied later So here when you say that field X has type Bob We're saying well doesn't have any particular type yet in this class But when we create an actual instance of Alice we specify what type Bob is going to be and so in one instance of Alice Bob could be a string in another instance. It could be an integer and so from one instance of Alice to the next The actual type of Bob can vary Same for Carol we say here that field Z is of type Carol But what type it is specifically will be filled in when we actually create an instance of Alice The compiler though for that instance will enforce consistency If I say that my field Z here is of type Carol And I say that also this method foo has a parameter B of type Carol then for my instance Whatever type Carol is whether it's a string or cat or a dog or whatever both the field Z and his parameter B Their types have to match up Same thing for the field X and the return type of foo because they're both Bob Whatever Bob's going to be for a particular instance of Alice those two types have to be the same So then down here if I create a variable a of type Alice I specify in the angle brackets for this particular Alice variable. What kind of Alice is it a Normal class a non-generic class is a blueprint for instances, but a generic class is like a blueprint for classes It's a blueprint for blueprints So I have to specify here particular types for Bob and Carol in this case I'm saying Bob will be an integer and Carol will be Boolean and here where I create an instance of Alice I also specify what the types for Bob and Carol are going to be and note that the types of my instance are matching up with the Type for my variable otherwise the compiler would not accept the assignment So on the next line when I create variable B of type Alice where Bob is float and Carol the string Then the instance of Alice I assigned to it has to have those same types When I then use a here the compiler knows a to have the type Alice where Bob is I and Carol is bool So when I set to field Z of a the compiler is expecting a Boolean and so this is about set operation When I get field X of a the compiler knows that field X for a is going to have the type int And so the value returned by this get can be assigned to variable I here of type integer When though we try and assign B to a or vice versa We'll get a compilation error because even though a and B are both instances of Alice Well the different kinds of instances and the compiler knows that so it doesn't consider a and B to have the same type Just to be thorough here if we're going to call foo on instance a well Then I look like this some floats and then Carol is going to be a Boolean So it's just a false so this is an acceptable call Because for instance a Carol is Boolean so it's expecting a Boolean for this last parameter and the call returns an integer So in short a generic class is a class which has type parameters in this case to Bob and Carol And for particular instances of the class we specify what those types will be So we can have a class where one or more types aren't necessarily locked down As we'll see in real C sharp what this is most commonly useful for our collection types things like lists and maps Because if you want to define a class representing say a list We want to be able to write just one class which represents lists of any type We want to be able to have lists of strings and lists of integers and lists of cats And we want the compiler to distinguish between those types so that it knows that a list of strings is not the same thing as a list of cats If I have an instance of my list class, which is supposed to be a list of cats I want the compiler to stop me if I try and add something to my list, which is not a cat That is what generics make possible