Programming with Visual C#

Uses Visual Studio Pro

Visual C# apps have a GUI, that includes:

  • Solutions Explorer – Area for browsing through files in your project
  • Properties Window – Used to change the properties of objects inside the designer
  • Designer – Graphical building suite
  • Output – Shows build status and helps understand bugs
    • error reporting isn’t always correct, but it is usually around the actual error, so it’s helpful

If you lose windows, use the view menu to display the different panels

Form Bounding Box

Property Window

When dealing with properties, you use the name of the property and a reference to the object.  You can manipulate object properties through the properties window.  Properties are components of the object, and we can access all properties through code as well.  We access properties with the member access key, or dot (.)  Your code takes precedence over your designer.

Add Controls to Forms

When you add controls to forms, you place them in special properties, the controls property of the form.  When adding controls and objects, you want to use proper naming conventions.  Follow the rules! 

  • Name a variable with what it is, what it does, and initials. 
  • No spaces! 
  • Never start with a number

Scope

Braces separate out different regions of code.  Each region is known as scope.  Variables within a particular scope are only available to that scope or any children.  There are different types of scope.  Function scope has full access to objects inside the function, denoted by {}.  Next up is object scope.  Means that everything in object has access to variable.  Object scope is higher than function scope.

Even higher is file scope.  In this, all object have access to all variables in file scope.  Highest up is project scope.  In this, we create global variables that are accessible to all parts of project.  Don’t do this unless you really have to, or it really really makes sense.

Namespace

Namespace can be considered as a wrapper.  To prevent the clashing of variables, code is wrapped in a namespace to separate programming libraries.

Objects are you classes, and methods are your functions.

Libraries

The libraries you import are called references.  You use the using keyword to access your libraries and attain the namespace to use any variables and methods contained within the library.

Message Boxes

Message boxes are useful when debugging.  We place strings inside of the MessageBox.Show() method. String literals are surrounded by double quotes.

Chapter 3

Performing Calculations

Calculations follow the order of operations.  We can use MDAS and modulus, which is the remainder of operator.  We use it to:

  • Modulus will always output between 0 and the number being modded
    • 3%3 = 0 while 4%3 = 1 and 5%3 = 2

If data types are mixed, graduate the simpler data type.

Statements are dicateted by operator precedence (MDAS and parens) and associativity (left to right).

User input and output is always a string, we must use parsing methods to change the ascii code values of the text and convert them to actual numbers

Parsing is looking at each item in a string and make decisions based on what we find.

Try – Catch

When exceptions occur, you can write try – catch statements to handle exceptions before the program dies.  If exceptions is thrown but not handled, program quits.  When exceptions occurs, our runtime state changes.

Try blocks are code that could possible have an exception.  If exception occurs within try, we then move to catch block of code.  We run the catch to try to fix the thrown exception.

Must have try – catch block whenever we use parse methods.

Named Constants

Named constants are blueprints and tell other programmers not to change the variable.  We don’t have to use these, but we might want to (will help with JS).

Fields

When variables are set at the object or class level (not inside a function), they are called fields and are available to call code inside the object.

TabIndex

We can specify how a user could tab through your form.  TabIndex of 0 sets focus at runtime.  You then want to set up tabIndex for how the form should be filled out.

We can also set focus with ControlName.Focus(); method

Debugging

The debugger allows you to examine the stack, which is automatically assigned memory that is managed by the operating system.  We can view what is on the stack by inserting breakpoints.  This is very useful for locating bugs

Breakpoints can only run on Runtime code (when you are performing processing, like assigning or computing).  Variable definitions aren’t runtime, so we can’t break on them.  However, if you declare and set the value at the same time, we can use that as a breakpoint.

Breakpoints stop code execution at the line set as the breakpoint.  Technically, it does not process the breakpoint line.  Once we reach the breakpoint, we can view what is in memory at that point. If we then step over the breakpoint, we run that line and inspect the results.

We can also add watch to portions of the code by highlighting sections and right-clicking, then click Add Watch.  With a watch, you can examine what the highlighted code

There are differences between error types.  Syntax errors are easy to spot because compiler will fail.  Logic errors are more difficult and can affect the result of your computations.  Debugging helps to understand these logic errors

Control Structures

Control structures are statements that determine which pieces of code will run.  If statements are great examples of control structures.

If statements

They only care about true and false.  The if statement evaluates an expression, and if true, we run the code within the scope (code inside the brackets).  If not, then we skip the code in the block.  If statements are great uses for boolean variables.

Booleans only have 1 of 2 values, True or False.  They are also referred to as 1 or 0, with 1 representing true.

If statements are run-time code.  We can also use relational operators when evaluating booleans.

  • >
  • <
  • >=
  • <=
  • == – Is equal to
  • != – Not Equal

If-Else Statement

If the if statement returns false, you can then optionally run an else statement.

Nested Control Structures

You can have if statements inside of if statements by nesting if statements inside the scope of other if statements.  They are used for complex decision making.  If going more than three nests deep, you need to rethink your logic.  Don’t let any control structure go beyond three nests.

If-Else-If

You can also set up your control structure to test many different expressions at once.  They read top-down, so make sure that your tests don’t overlap eachother.

Logical Operators

We can use the logical AND && or OR || to join logical operators together.  We also have !, which represents not and negates or reverses the value.  The ! is a unary operator, not a binary operator, and only acts upon one operand.  It is also right to left associativity.  Changes a 1 to 0 or 0 to 1, making true false and false true.

Bool Variables and Flags (sentinels)

Logic that sets true or false values with booleans, then we use if statements to review these booleans and perform a decision.  The boolean value is called a flag and is a variable to signal the condition of a program.  They are also used to set system state.

Comparing Strings

We can use the comparision operator ==, the != operator, and the string.compare function to compare two strings.  The first two are case sensitive, the last one returns a 0 if the strings are the same and 1 or -1 if they are different (negative shows the direction in which they are different)

Preventing Data Conversion Exceptions

We can validate data with TryParse methods, using inputs to validate our input.  When using text input, we must use Try – Catch or TryParse with an if statement.

Affordances

Use the proper controls to not allow your lusers to make mistakes.  If they need to select from a group of options, always use radio buttons.  If they can select multiple options, always use check boxes, etc.

Event Handlers

In C#, everything is an object.  This means that the objects that send events can be unpacked to reveal the actual control that sent the event.

Switch Statement

Switch statements can increase the efficiency of your program and is useful for a set of if-else-if statements.  Use the case statement to test your expression, then use the break statement to leave the switch block after we get a match.  When designing, you can start with if statements then refactor into switch statements.

List Boxes

List boxes are very important controls that are a step into spreadsheet controls. List boxes are string bases, in fact, all input is strings and output is string. They are used often in programming, so we want to be effective with them.  We use the items to place strings inside the list boxes.  We can use SelectedItem in a list box, which represent the text of the item selected.

SelectedIndex is different in that we are referring to the item by its index, starting with 0.  We can also use SelectedItems and SelectedIndices.  When working with selected index, use brackets for array notation.

One thing to watch for is an index of -1.  If you list box selected index is -1, then no item has been selected from the list box.  We must control for this!

Iteration

Anything we do on computers with an importance requires repitions.  The most important control structures we use are decision structure and looping structres.

While Loops

Control structure based on a boolean flag.  While true, it continues repetition of the statements enclosed.  While loops have their own scope.  We use the while clause to test a boolean.  If true, it completes the statements and heads back to the eval.  If still true, it completes statements again and heads up to the eval.  Once false, it completes the scope.

While loops are dangerous if they don’t have a mechanism within themselves to terminate the iteration.  While running, we are prevented from working with the program, so we need to be able to control our loops (mostly with counter or flag variables).

Best practice states that when using counters, you init them to 0 and only use < or > evaluations, not <= or >=.  This makes it easier to see how many times the loop will iterate.  Counters are also called accumulators.  While loops are pretest in that the expression is evaluated before every iteration of your code.

Prefix Vs Postfix

Adding the ++ or — before the variable name increments or decrements BEFORE any other expressions on the same line are evaluated.  Postfix is the opposite.

For Loops

These are the main loops that we should use BEFORE any other looping structure.  In them, we use an initialization expression, a test expression, and an update expression.  For loops have this level of control, so they are great for bug prevention.  Be sure to declare counter variables within the scope of the for loop.  Use the variable name i and j for any nested for loops. For loop is a pretest loop, meaning the expression is evaluated before the body statements are run.

Do While Loops

This is the example of post test loops.  Dont use these unless you have to.  This will run the code in the code block before.

File Accessing

Files are composed of two different types of files, binary and text.  Image files are binary.  TXT files are text files.  Office files are binary.  Most everything of worth is in a binary file, meaning that the file is composed only of 0 and 1’s.  Text files are composed of ASCII characters, and provide an into binary files.

With binary files, we are saving our variables to file with the ability to readily overwrite any variables already in the file.  This is different from text files in that you write text strings to the document and changing them involves changes to anything else in the text file.  For example, if you wanted to add a number to a text file, you would shift all the other numbers and variables in the file to the right.

System.IO

A library with methods for writing and reading data from files.  To add this library, add the using System.IO statement to the top of the Form.cs file, beneath the other references.  When working with file input and output, we need to specify which file we are opening and where we are opening it.

We use the Streamwriter to open files for writing.  We then use the .write method to actually write data to the file.  We must then remember to close the file to guard against any side effects.  If not explicit path is given, the file will be saved to the same folder as the executable file.  Use implicit paths (not specified) when you are writing files that you need for your application.

SaveFileDialog

A newer inclusion, the saveFileDialog allows the user to choose the file name for the file we are writing.  To use it, add the control to your form, then create a .Filter to determine what type of data the file will allow.

Important to use double slashes // selecting paths because a single / denotes an escape character, so we need double // to tell the computer that we really want a slash /.

Random Number Generation

Experimental vs theoretical probability means that a coin has a theoretical probability of landing on heads or tails 50% of the time.  In experiment, you likely won’t observe this.  If you flip 10 times, you might get 7 – 3.  However, if you flip more, the number will move towards the theoretical probability.  At some point, if you flip enough times, you will achieve the exact probability that you theorize.

Seeding

When you seed the random object, you have to seed it with a unique value.  Epoch is when the computer clock starts.  Computers tell time in milliseconds from January 1st, 1970.  The bios tracks every millisecond, and it is called the epoch.  This is the perfect seed, it is random and a big number and will always change.

Use of Modulus for Random Number Generation

Use modulus to constrain numbers into a range.  If you use N % 3, every output will be between 0 – 2.  If you have N % 7, every output will be between 0 – 6.  This is important to understand!

Methods

Procedural programming relies on functions to change the data, whereas object oriented programming places the data inside objects that organize the variables and functions.  They wrap around the data (variables) and contain the runtime code (functions) that manipulates the data.

Procedural programming is organized by object oriented programming.  Within the object, they are programmed in a procedural fashion.

Methods are used to break complex programs into pieces.  This process is called modularization.  When building methods, think about how that method can be reused.  Make your methods do one thing and do them very efficiently.

Void methods do not return any values, they only take data then terminate.  Value method can return a value after the method finishes.

Methods are both definition code and runtime code.  We must define what the method receives and what it returns.

Debugging Methods

When debugging methods, you need to use the step into command to move into the function and

When you call a function, that function is placed on the stack and then popped off when the function is completed.  Every variable and function you create goes onto stack, which is automatically allocated ram.  If your methods call themselves and run infintely, you will blow your stack.

Winding the stack refers to following your code through levels of the stack.  As functions are called within functions, we burrow ourselves deeper into the stack.  We then must move out of each layer because when you call a method it must then return to it’s calling place.  This can be complex.

Void Methods

You have 4 parts to a method.

  • Public or Private
  • Void or return
  • arguments – what the function accepts
  • body – runtime code that does something when function is called

Return Point

2 ways to get an answer back from a function.  You can use the out keyword or you can use the return keyword.  Return tells the code to go back to the starting point.  You can return values with the return keyword.

Arguments

Arguments are pieces of data that are passed to functions.  When the argument is a variable, that is called a parameter.  Arguments is probably the most important aspect of methods.

We don’t usually need to pass variables to methods anymore.  Most methods that we create will act upon the variables that are already contained within the object.  Methods are used to access and manipulate the data stored within the object.

Arguments always go within the parenthesis.  We first need to define our method in definition code, along with the data type of any arguments.  An argument can accept any data type, from primative to complex.  We can pass objects as arguments, but that is more complicated.  You can also pass multiple arguments to methods, but the method has to expect them.

Named Arguments

Arguments are used in the order they are expected, but we can choose where

Default Arguments

We can set a default argument that will be used by default if no other argument is sent.  The argument looks like (decimal taxRate – 0.07m).

Passing Arguments by Reference

The scope of your arguments is different the scope of you calling function.  When you change a variable within the method scope, it doesn’t necessary change anything in the scope of where the function is called.  If you want to link the variables, we can pass our arguments by reference.

We need to expect the reference argument with myMethod(ref int number).  We then need to specify the reference argument in the function call (myMethod ref myChosenVariableName).

We can also use the output parameter to do something similar.  In this instance, specify the output argument with myMethod(out int number) and the method call with myMethod(out myChosenVariableName).  I don’t understand the difference between the two.

Value Returning Methods

We use the return statement to return a value from a method.  When using these, we must make sure to declare a variable to hold the return value. If you have a lot of values to return, don’t use the return statement and instead use pass by reference.

Boolean Methods

The method detects whether something is true or not, then returns the boolean value

Stack vs. Heap

The stack is memory that is already pre-allocated for our program.  The heap is all other memory out there that we can possibly use.  We need to ask for this.  Pointers are automatic stack variables that store the memory address to a location on the heap.  You only need to access the heap if you need more memory than the operating system is providing.

Objects in OOP are all reference types.  Primative data types are quasi-reference.  Our objects have our data, and functions are used to manipulate this data.  When defining objects, we define what data is in object and which functions manipulate the data.  Objects hold memory and protect that memory.

We must validate data by setting up accessors.  These are public functions that manipulate the data.  Use a default set and get methods.We use these methods to set up read and write access for the data inside the object.  When building objects, we are programming for other programmers to use our objects.  They need to be perfect.

Often, we will want to automatically set up the data inside the object at the time we instantiate it.  We do these with constructors.  Constructors are used to set the data inside an object.  Common things you want to do with objects are  :

  • set up variable values

Constructors are used to pass data inside the object to assign the variables inside the object.  Must use default constructor and overloaded constructor.  The overload will have a data type or the this keyword.  Constructors can give us multiple ways of instantiating the object.

Memory Leak

When too much memory is being allocated, you are unable to use that memory again until that memory is released.  This is called a memory leak.

Arrays

Arrays are also known as contiguous memory.  Arrays are connected by pointers that are actually in order in on the physical chip.  Arrays are reference type that points to the first block of contiguous memory.

MultiDimensional Array

I don’t know how we use these, so do some research 🙂  These would form matrices.  I guess the rule of thumb is to not go beyond 3 levels in the matrix (3 x 3 x  3).