I wrote this for a friend who's changing careers into the software development world.
Index:
Debugging: the reason your keyboard has F-keysComments & Conventions: where, what, when, and when not
Operators and special characters: comparison, action, logical, and bit-wise.
Namespaces: two ways to use them and why they matter
Data Types: int, Int, Integer, and FlyWings.
Accessibility: I can see infinity...
Variables: Strong Typing and Conversion, this is where Coding goes Catholic!
Properties: Variables with smarts!
Constants: They're not variable...
Do that again... 4 types of loops: for, foreach, while, do..while
Decision makers: if..else & switch..case; or, IF(beerInHouse.Amount == 0) THEN HaltAndCatchFire()
GOTO: The Bane (or Salvation) of all Humanity
Did you mean "Is" or "Equals"? =,==,+=,*=, and all the ways the "=" symbol is used in C#
Methods: Take This, Do Something With It, And Give Me An Answer
Enums: (un)limiting your options
Collections, part 1: Arrays! Dimensions, creation, accessing, limitations
The Four Buzzwords: Inheritance, Abstraction, Encapsulation, Polymorphism; part 1
The Four Buzzwords: Inheritance, Abstraction, Encapsulation, Polymorphism; part 2
The Four Buzzwords: Inheritance, Abstraction, Encapsulation, Polymorphism; part 3
The Four Buzzwords: Inheritance, Abstraction, Encapsulation, Polymorphism; part 4
Debugging: the reason your keyboard has F-keys
"Debugging" is the name for a process of running a program in a partially-open state, so that you can look inside it at the inner workings. To begin debugging an application in VS, simply press the F5 key (Or use the menu: Debug > Start Debugging). This will compile your program and include a special .pdb file that allows the debugger (in this case, VS) to 'follow along' with what's happening inside the application. This can let you view the specific lines of code that are executing, or the values of variables at a specific instant in the program's execution.
In order to work in detail with parts of the program, you'll need to add one or more "Breakpoints" to your code (do this by clicking in the left margin of a specific line of code, you should see a small red circle appear and the line will be highlighted in red). These are points where the debugger will pause execution of your application until you tell it to keep going. Once the execution is paused this way, you have 3 keys you can use to manipulate the code: F5 will simply continue execution until the next breakpoint is reached; F11 will "Step In" to the current line of code, meaning that if the line contains a Method call that you have the source code for (i.e. you wrote it), you will be redirected to the method implementation so that you can step line-by-line through the method implementation, and then return back to the calling code; and F10 will "Step Over" the current line of code, meaning that the line will execute, but if the line contains a method call the method's entire action will be done without redirecting to the implementation.
Example:
Create a new WinForms project with a single button called "btnGo", double click the button to create a click handler for it, and copy the following code into the click handler:
for(int i=0;i<10;i++)
counter = counter + i;
btnGo.Text = counter.ToString();
Place a breakpoint on the 3rd line (counter = counter + i;), run the application, and click the button. Notice that you have a window at the bottom called "Locals" and it will show the current value of "counter" and "i". Press F5 several times to see the changes to each of these variables as the loop repeats. Stop the program, remove your current breakpoint, and place a breakpoint on the second line (for...). Run the application and click the button, but this time press the F10 key several times to see how the program steps through the internal parts of a for loop as you press the key for each component.
Comments & Conventions: where, what, when, and when not
Most of the time, you want to make your class, method, and variable names logical and clear for their purpose. This creates "self-documenting code", since it's more-or-less human readable. But sometimes, the specific logic of what you're attempting to do, or why you're having to do something, isn't obvious: when this is the case, you should put specific comments in place so that other readers (including Future You) will be able to understand what you've done. There are 3 types of comments in C# with one being a special case: single-line comments are simply "//", and anything after those two characters on a line will be ignored; multi-line comments must be wrapped in "/*...*/"; and the special case are called Summary comments, are used for IntelliSense, and are created by typing "///" before a class, method, or property name.
There's two major types of Conventions to be aware of: Casing and Typing, and combinations of these can be used for other 'convenience conventions'. Casing conventions are typically resolved as either PascalCase or camelCase. The difference is that in PascalCase the first letter of each word is capitalized, while in camelCase the first letter of the first word is not capitalized. Typing conventions basically boil down to either the use or non-use of Hungarian Notation: for variable names when using Hungarian Notation, the data type of the variable is included as part of the variable name (e.g. "public string strName", or "public int intNumber"). Both of these conventions are only a preference (nothing in the complier cares one way or the other), but it is best to be consistent with whatever conventions are already established for whatever team you're working with. Examples of convenience conventions can include using PascalCase for public methods/variables and camelCase for private/internal ones, or starting all private variables with a "_" character, or other such nonsense to help identify code. Most of these convenience conventions are irrelevant with modern development environments like VS, but they're still used out of habit.
Further Reading: https://msdn.microsoft.com/en-us/library/ff926074.aspx
Operators and special characters: comparison, action, logical, and bit-wise.
Honestly, just read the further reading stuff. Operators are pretty straight-forward, but you should know the order of operations for them and what they do.
Further reading: https://msdn.microsoft.com/en-us/library/6a71f45d.aspx
Namespaces: two ways to use them and why they matter
Namespaces are used to specifically clarify the origin and purpose of a set of code. These allow a developer to create classes that have the same name as another class (even one they didn't create), but without any conflict or strange interaction between the two. They can be nested within each other in order to clarify the purpose of a piece of code, or to limit access to a section of code (see the "internal" keyword).
You can reference a namespace one of two ways: either through a using keyword declaration at the top of the file, or by deliberately typing out the specific namespace as part of referencing a class or other code within.
Further reading: https://msdn.microsoft.com/en-us/library/0d941h9d.aspx
Data Types: int, Int, Integer, and FlyWings.
All data types are classes, all classes can be data types. The only tricky parts to learn are the fact that some data types are synonymous with each other (e.g. "int", "Int", "Integer", and "Int32" are all the same thing); and the various sizes and limitations of the different types (such as how large a number can be stored in an Int16, an int, or a BigInt; or how long a string variable can be).
Further reading: https://msdn.microsoft.com/en-us/library/cs7y5x0x(v=vs.90).aspx
Accessibility: I can see infinity...
Access modifiers (i.e. public, private, etc.) are used to control who can see and/or use a specific class, method, variable, or other entity. This allows you to protect certain parts of your application from being accessed incorrectly, from receiving 'unsafe' values, or other similar scenarios. Consider the following code:
{
Admins.Add(currentUser);
}
public void PleaseGrantAdmin(User currentUser)
{
if (currentUser.IsAdmin)
giveAdmin(currentUser);
}
If the giveAdmin method was public, then other developers would be able to write incorrect code that would accidentally give everyone Admin privileges. Sometimes, you will use access modifiers to protect your code against intentional misuse, but most of the time you will use access modifiers to protect other developers (including Future You) against their own ignorance or stupidity.
Further reading: http://stackoverflow.com/questions/614818/what-is-the-difference-between-public-private-protected-and-nothing
Variables: Strong Typing and Conversion, this is where Coding goes Catholic!
Ok, so not Catholic. But they do convert!
C# is a Strongly-Typed Language. This means once a variable is declared as a specific data type, it will always be that data type. You can potentially cast the variable as another data type, but it doesn't change the actual variable's type, just how you access the object the variable is pointing to.
Further reading: http://en.wikipedia.org/wiki/Strong_and_weak_typing
C# allows for both Value and Reference variables. The differences are nuanced, but they boil down to: Value variables are the actual object the variable points to, while Reference variables refer to the object. This matters for memory management (Value variable objects go away quickly, Referenced objects must be cleaned up by the Garbage Collector), passing parameters into methods, and a handful of other things like performance issues that are really quite trivial on modern hardware. Most of the time you won't need to worry about whether you're using Value or Reference variables, you just need to be aware of what you're passing in as the parameters of a method and how your actions in the method will affect those values.
Further reading: https://msdn.microsoft.com/en-us/library/4d43ts61(v=vs.90).aspx
Further reading: https://msdn.microsoft.com/en-us/library/0f66670z.aspx
Implicit typing is a unique (and often argued-about) edge case: it allows a variable to 'figure out' its type from what is assigned to it. Implict typing is done by using the var keyword as the 'data type' when declaring a variable, and requires that a value be assigned to that variable as part of the declaration. At first, this would seem like it is a 'weak' typed variable mechanism within C# since you aren't specifying the data type, but remember, the C# language is always strongly-typed, so these variables cannot change their type once they're assigned.
Further reading: https://msdn.microsoft.com/en-us/library/bb384061.aspx
Properties: Variables with smarts!
Properties are an extension of the idea of a variable: they're a way to store something. The difference is that you can define behaviors for a property so that it can actually perform actions when it is accessed or assigned to. These actions could be as simple as fetching or assigning the value for an internal/private variable, or could be as complex as validating inputs or initializing other objects.
Further reading: https://msdn.microsoft.com/en-us/library/x9fsa0sw.aspx
Properties can also be used for a very useful technique called Lazy Loading: loading an object only when it is accessed. This technique has several advantages (including only consuming as much memory and other resources as is actually needed for the currently-executing portions of the program) and disadvantages (such as potentially requiring multiple connections or round-trips to a server or database), but is very powerful when implemented correctly.
Further reading: http://en.wikipedia.org/wiki/Lazy_loading
Further reading: http://www.codeproject.com/Tips/620215/Four-Ways-to-Implement-Lazy-Loading-in-Csharp
Constants: They're not variable...
Three things to know about constants:
- They're still variables in every way, you just can't change their value, ever, throughout your entire program's execution.
- Because they can't change, they can only be declared for the primitive types (e.g. int, string, etc), and so you cannot have constant methods, properties, or events.
- They're way over-used, mostly by old-school developers trying to avoid (or cause, jerks) "magic numbers". You'll rarely need them in normal development.
Further reading: https://msdn.microsoft.com/en-us/library/ms173119.aspx
Do that again... 4 types of loops: for, foreach, while, do..while
When you want to do something more than once, you need a way to loop your code. There are four built in ways to do so, and each has its own advantages, disadvantages, and use cases:
- for
Requires you to specify a control variable, a comparison condition, and a way to change the control variable. You can then access the control variable within the statement, so this is frequently used to step through a collection of items by specifying the index to work with. Because you have control of the variable and how it changes, you can change it in interesting ways, such as only going through even values, or going through it backwards.
Further reading: https://msdn.microsoft.com/en-us/library/ch15axte(v=vs.90).aspx
-
foreach
Only works with Collections, and requires that the collection implement the IEnumerable interface, but makes creating a loop to do the same thing to everything in a collection super simple. This is one of your most commonly used tools.
Further reading: https://msdn.microsoft.com/en-us/library/ttw7t8t6(v=vs.90).aspx
-
while
This loop checks the specified comparison, and if it is true it then executes until the specified comparison is false. This requires you to have something in your code that will change the value(s) in the comparison, or else you're stuck with an infinite loop.
Further reading: https://msdn.microsoft.com/en-us/library/2aeyhxcd(v=vs.90).aspx
-
do..while
This is exactly like the while loop, except that it will always execute the code at least once before checking the comparison.
Further reading: https://msdn.microsoft.com/en-us/library/370s1zax(v=vs.90).aspx
Further reading: https://msdn.microsoft.com/en-us/library/ms228598(v=vs.90).aspx
Decision makers: if..else & switch..case; or, IF(beerInHouse.Amount == 0) THEN HaltAndCatchFire()
If..else statements are pretty much a staple of all programming languages and the function more or less the same, just with some minor nuances.
With an if..else statement, any sort of comparison expression can be used or any property or method evaluated, so long as the result is a Boolean value (True or False).
In C#, there's about 3 things to know about if statements:
- The comparison should be within a pair of parenthesis (e.g. "if(i < 5)").
- If more than one statement should happen when the condition is true, wrap them in a pair of curly braces ("{}"). Otherwise it will just execute the first statement after the "if" statement.
- You can chain statements using the "else if.." statement.
Further reading: https://msdn.microsoft.com/en-us/library/5011f09h.aspx
An alternative to the if..else statement that can be used in-line is the trinary operation. It works based on the ?: pattern, and is often contained in parenthesis for clarity.
For Example:
Further reading: https://msdn.microsoft.com/en-us/library/ty67wk28.aspx
The switch..case statement is an alternative to the if..else statement and is frequently used, instead of a long chain of sequential "if..else if..else if..else" statements, when an evaluation would have several possible specific values. Unlike the if..else statement, you do not specify your own expression, instead you merely specify the values for the left and right side of an "is equal to" comparison. Because of this, switch..case statements can only be used with primitive data types or enumerations ("enums"). For example:
{
case "left":
this.HorizontalAlignment = Align.Left;
break;
case "right":
this.HorizontalAlignment = Align.Right;
break;
default:
this.HorizontalAlignment = Align.Center;
break;
}
Further reading: https://msdn.microsoft.com/en-us/library/06tc147t.aspx
GOTO: The Bane (or Salvation) of all Humanity
Ah, the mighty GOTO statement. This thing starts nerd arguments like nobody's business. Here's the short version: Yes, it exists, Yes, it has a few extremely rare edge cases where it is actually the correct solution (and/or the only solution), but No, you'll never encounter those situations until you're 6+ years down the road (if ever). So, the answer is: don't use it, don't ask about it, and ignore the trolls.
Did you mean "Is" or "Equals"? =,==,+=,*=, and all the ways the "=" symbol is used in C#
The number one error you will encounter throughout your entire programming career is this: = and ==. A single = is an assignment operation, while a double (==) is an equality comparison operation. The differences in the various operators involving the equals sign is worth taking careful note of, so review those comparisons.
Further reading: https://msdn.microsoft.com/en-us/library/6a71f45d.aspx
Methods: Take This, Do Something With It, And Give Me An Answer
So a class is an object: it's a thing, but in order to get actions, you need Methods. Methods are the verbs to a Class's noun.
A method's structure is very simple: a signature and a body. The method signature breaks down into three parts:
- A method name
- Zero or more inputs (or possibly outputs, more on that later) called "parameters" or "arguments"
- A return value (which can be 'void', indicating no return is expected)
The method body simply consists of the actions the method should take. This can include any C# commands, including calling other methods.
Best practices:
- Method names should be action-oriented and describe the action they will take (e.g. "AddTwoNumbers", "GetAllOrders", or "GetOrdersByType")
- Parameters should be clearly named to indicate their desired values
- A method should only attempt to complete one action. If you need to complete more than one, subdivide the actions into separate methods and call each of them in order. For example, instead of creating a method called "GetAllOrdersThenFormatThemAndDisplayThem", you could instead create three separate methods ("GetAllOrders", "FormatOrders", "DisplayOrders") and a 'wrapper' method ("ShowAllOrders"). This will make reuse and debugging much easier, and Future You will thank Present You for having done so.
Further reading: https://msdn.microsoft.com/en-us/library/ms173114.aspx
Enums: (un)limiting your options
An "Enum" (or Enumeration) is a mechanism that allows you to clearly define a set of options for a custom-made data type. For example, you could have an enum of "DaysOfTheWeek", with the values "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", and "Sat"; this would both allow other developers (including Future You) to specify a variable of type "DaysOfTheWeek" and use any of those values (including get IntelliSense listing those values), and restrict those same developers to only use those values.
Further reading: https://msdn.microsoft.com/en-us/library/sbbt4032.aspx
Collections, part 1: Arrays! Dimensions, creation, accessing, limitations
Almost every program you ever write will at some point need to deal with sets of things. In programming terms we refer to these as Collections, and the base of nearly every type or variation on the collection is the Array.
An array is simply an object that can contain multiple other objects. Arrays are type-specific, so you declare what Type of objects will be stored in the array when you declare the array.
Declaring an Array is very simple:
Accessing an element of an array is also very simple:
The arrays in the examples above have only a single dimension, but arrays in C# can have multiple dimensions. There are two ways to accomplish this, Multi-Dimensional Arrays and Jagged Arrays, and the difference between the two can be very confusing if you don't understand them. The key difference is that a multi-dimensional array has multiple coordinates in the index (e.g. "int[,] ticTacToe = new int[3,3];" creates a multi-dimensional array with two dimensions that are each 3 elements in size), while a jagged array has multiple indices (e.g. "int[][] MechCritSlots = new int[6][];" creates a jagged array with 6 elements in its first dimension, each of which is an array with their own definition for the number of elements in their (second) dimension). A multi-dimensional array is used when you will always have an equal length for all items of a higher dimension (e.g. in the 3x3 ticTacToe illustration, all of the second-dimension elements will always have 3 elements), but a jagged array allows you to have different lengths in the higher dimensions (e.g. in the MechCritSlots illustration, the first slot could have a second-dimension array of length 4, while the next slot has a length of 8). Both have their place, but they can be confusing if you're not careful with them.
Further reading: https://msdn.microsoft.com/en-us/library/9b9dty7d.aspx
The Four Buzzwords: Inheritance, Abstraction, Encapsulation, Polymorphism; part 1
Four keywords define the most important components of Object-Oriented Programming and the most commonly confused (or even ignored) concepts: Inheritance, Abstraction, Encapsulation, and Polymorphism. Each of these words defines a behavior that is critical to the nature of Object-Oriented Design, and thus critical to Future You's success as a developer, and each of these behaviors is closely linked with all of the other behaviors. In this session, we'll cover the first one: Inheritance.
Inheritance describes the behavior of a class that is based on another "parent" or base class, reusing all of the properties and methods of the parent class and extending or replacing them with properties and methods of its own. The new class is often called an extension class, derived class, or sub-class. This behavior allows you to design features that will be commonly used in multiple classes as part of the base class, and then only implement the unique differences in the sub-classes, making sub-classes more specific versions of the parent class.
For example, if you want to define several classes such as Duck(), Goose(), Chicken(), and Sparrow(), each of those classes will have several shared characteristics and methods, such as .RuffleFeathers() or .FlapWings(). At the same time, they will each have unique characteristics such as how they implement .Fly(), .MatingSounds(), or .Consume(iFood). So while you may need to write unique code for each fowl, there's no reason to re-write the shared code among all of them, when you could instead create a Fowl() base class and implement that code once in that base class. This makes maintenance of that shared code easier, as you do not have to try to remember to maintain the same code over and over in multiple locations. For example:
{
public string Name;
public string RuffleFeathers()
{
return this.Name + " ruffles its feathers!";
}
}
public class Duck : Fowl
{
public Duck()
{
this.Name = "Duck";
}
public void Swim();
{
/* do stuff */
}
}
public class Chicken : Fowl
{
public Chicken()
{
this.Name = "Chicken";
}
public void Cluck();
{
/* do stuff */
}
}
public class Program
{
public void Main()
{
var flappyThing = new Duck();
flappyThing.RuffleFeathers();
flappyThing = new Chicken();
flappyThing.RuffleFeathers();
}
}
Further reading: http://en.wikibooks.org/wiki/C_Sharp_Programming/Inheritance
https://msdn.microsoft.com/en-us/library/vstudio/ms173149(v=vs.140).aspx
The Four Buzzwords: Inheritance, Abstraction, Encapsulation, Polymorphism; part 2
The next 'buzzword' concept is Abstraction, and while some (*cough*MS C# Programming Guide*cough*) might not consider it to be one of the foundational pillars of good code design, I think it's probably the most important of all of them.
Lets get meta for a moment, as there are two different types of abstraction to talk about: Abstraction The Principle, and Abstraction The Mechanism (which is a concretion of the principle. I told you, meta...).
First, lets talk about Abstraction The Principle. The Principle of Abstraction is based around the idea that you should only be as specific as you ABSOLUTELY must be. By preferring to be generic instead of specific (or in programming terms: abstract instead of concrete), you make your design more flexible and adaptable, more readily able to accept change and allow reuse. A real-world example of this is renting a car: you tell them that you need to rent a car and they will provide you with "a car", but if you're more specific ("I need a red 2-door convertible domestic sports car") they'll be more specific also. So the take-away from this is to try to avoid being too specific with what you're doing: don't use Int64 when you can just use int, don't use a StringBuilder when you can just use a string, and so-on.
So if Abstraction The Mechanism is the implementation of what we just learned, then it is more specifically focused on how to 'be abstract'. In C#, actual abstraction breaks down into two things: abstract classes, and interfaces. Abstract classes are the simpler of the two, but also the more odd to find ideal use-cases for, because they are exactly what they sound like: they're everything a class is (properties, methods, and constructors), but not specific. Abstract classes cannot be instantiated as objects by themselves, and instead only provide a framework and some common logic so that other classes can extend them into full objects. The one downside to an abstract class comes from one of the core design components of the C# language: a class can only extend one other class, so you cannot extend multiple abstract classes.
In the example from Inheritance above, the .Main() method instantiates a Duck() object and a Chicken() object, but it just as easily could have instantiated a Fowl() object. This would have caused some problems, because the Fowl() class doesn't have a value for its Name property. To protect against this (and since Fowl() is merely an abstraction of Duck() and Chicken()), we could declare the Fowl() class as an abstract class, and then the .Main() method would not be able to actually instantiate a Fowl() object.
Interfaces are even more flexible than abstract classes, as they're merely a contract of what properties and methods an object will have, and cannot contain any of the logic of how those properties or methods work. While an abstract class can have common logic already implemented to be shared among child classes, classes that implement an interface must individually implement each of the methods defined in the interface. While this sounds like a major downside, the advantage interfaces have over abstract classes is that a child class can implement as many interfaces as you like. (Note the difference on Implement versus Extend).
Further reading: https://msdn.microsoft.com/en-us/library/ms229019(v=vs.110).aspx
The Four Buzzwords: Inheritance, Abstraction, Encapsulation, Polymorphism; part 3
Encapsulation is often confused for abstraction, but while similar techniques can sometimes be used to accomplish the goals of both terms, the actual reasons and objectives for the two are vastly different.
While abstraction is all about giving to other coders and other code (by giving contracts or abstract methods) with great transparency, encapsulation is all about restricting what other code and other coders can see and do with your code by limiting the visibility of various members of your code. This can make encapsulation one of the most difficult concepts to know when to apply, as it's typically easiest to make a blanket decision of "No, nobody can get to my code outside of my code" or "Whatever, it's all public and I don't care", but Future You will be much happier when they don't have to figure out the mess of Current You's code and decide what's valid for reuse and what's not. The default accessibility (unless you specify something different) for C# is to make everything private, so take the time during development to evaluate your properties and methods and decide whether they need to be exposed at all, and if they do need to be exposed, just how open they need to be.
The mechanism of encapsulation that sometimes gets confused for abstraction is to use parent or helper classes to contain the encapsulated properties or methods. Because this mechanism is shared with abstraction, the two are often intermingled, so it is important to consider your goals for both encapsulation and abstraction when creating these separate classes.
Further reading: http://en.wikibooks.org/wiki/C_Sharp_Programming/Encapsulation
The Four Buzzwords: Inheritance, Abstraction, Encapsulation, Polymorphism; part 4
Polymorphism is one of the most powerful and most invisible aspects of an object-oriented programming paradigm. The word means "Many Shapes", and very accurately describes the concept: because C# is an object-oriented design paradigm implementing polymorphism, entities (objects) can be (and therefore be referenced as) more than one type. This magnifies the power of inheritance, abstraction, and encapsulation by allowing multiple layers of each to apply to the same entity. As an example:
{
public string Name;
public string Color;
public string ModelYear;
public virtual void RevEngine()
{
Console.WriteLine("Vroom, vroom!");
}
public virtual void GetInfo()
{
Console.WriteLine(string.Format("I'm a {0} {1} {2}", Color, ModelYear, Name));
}
}
public interface IRunsOnGas
{
public decimal FuelTankLevel;
private decimal maxFuel;
public void AddGasToTank(decmial gasToAdd);
}
public class Car : Automobile, IRunsOnGas
{
public Car(string name, string color, string modelYear, decimal maxFuel)
{
this.Name = name;
this.Color = color;
this.ModelYear = modelYear;
this.FuelTankLevel = 0.0m;
this.maxFuel = maxFuel;
}
public void AddGasToTank(decmial gasToAdd)
{
if(FuelTankLevel + gasToAdd <= maxFuel)
FuelTankLevel += gasToAdd;
else
FuelTankLevel = maxFuel;
}
}
public class Truck : Automobile, IRunsOnGas
{
public Truck(string name, string color, string modelYear, decimal maxFuel)
{
this.Name = name;
this.Color = color;
this.ModelYear = modelYear;
this.FuelTankLevel = 0.0m;
this.maxFuel = maxFuel;
}
public override void RevEngine()
{
Console.WriteLine("VROOM, VROOM!!!");
}
public void AddGasToTank(decmial gasToAdd)
{
if(FuelTankLevel + gasToAdd <= maxFuel)
FuelTankLevel += gasToAdd;
else
FuleTankLevel = maxFuel;
}
public int UsedCargoSpaceInSqFt = 0;
private const int maxCargoSpaceInSqFt = 24;
public void AddCargo(int cargoSqFt)
{
if(UsedCargoSpaceInSqFt + cargoSqFt < maxCargoSpaceInSqFt)
UsedCargoSpaceInSqFt += cargoSqFt;
}
}
public class Electric : Automobile
{
public Electric (string name, string color, string modelYear)
{
this.Name = name;
this.Color = color;
this.ModelYear = modelYear;
}
public override void RevEngine()
{
Console.WriteLine("whirr, whirr...");
}
public override void GetInfo
{
Console.WriteLine(string.Format("Hello, I am a clean-running {0}, manufactured in {1}, sporting a stylish {2} paint-job", Name, ModelYear, Color));
}
}
public class Program
{
public void Main()
{
// create the garage and add automobiles
Automobile[] garageSpaces = new Automobile[3];
Automobile[0] = new Car("Honda Accord", "Red", "2013", 15.0m);
Automobile[1] = new Truck("Ford F150", "Silver", "2014", 19.0m);
Automobile[2] = new Electric("Tesla Model S", "Black", "2015");
// fuel them
foreach (Automobile item in garageSpaces)
{
if (item is IRunsOnGas)
((IRunsOnGas)item).AddGasToTank(20);
}
// Find out what they are and rev them up!
foreach (Automobile vehicle in garageSpaces)
{
vehicle.GetInfo();
vehicle.RevEngine();
}
}
}
In this example, we define a parent abstract class Automobile and an interface IRunsOnGas, implement them as needed in 3 separate sub-classes, and then load and consume them in the final program. Notice in the program that we're able to address all of them as Automobiles, but due to the wonders of polymorphism we're able to see if some of them are IRunsOnGas, cast the object to that interface, and call methods described by that interface.
Further reading: http://en.wikipedia.org/wiki/Polymorphism_%28computer_science%29