C#

Introduction

portrait WW CookThe most efficient way to learn C# is to use Microsoft Visual Studio. C# is a Microsoft product that takes the features from C++ and Java and then adds Microsoft .NET controls. It is an Object-Oriented Language that is used by many companies to develop their software. The free download for Microsoft Visual Studio is the Visual Studio Community edition. This is a full IDE that allows compilation for multiple platforms. This section will go over some of the basics parts of writing C# code.

Sections

  1. Training
  2. Looping
  3. Structures, Classes, and Inheritance
  4. Exceptions
  5. Tasks (including Asynchronous)
    1. Race Conditions
  6. Abstract and Sealed Classes plus Virtual Methods
  7. Interface Classes

Training

I am using two main sources for my training. They are both developed by Microsoft Engineers. The Microsoft Virtual Academy is one directly sponsored by Microsoft. It allows you to take the courses and test your knowledge to gain certification. The other is EdX, which isthe course I took. It also has a certification option for $90.00. When I include certain concepts, the information is a combination of my knowledge and information from these two courses.

I earned my C# Certificate through EdX.

Looping

Looping is one of the basic constructs of C# and can be done in one for three basic ways:

  1. For loop
  2. While Loop
  3. Do loop

The For loop has the beginning value set in the statement itself, while the While and Do loops depend on the programmer setting the initial value before the loop is entered. For consistency, I set the initial value of all three even though it will be reset for the For Loop. The For and While loops do their checks before the loop is opened. The Do loop checks at the end of the loop for the termination value, thus always executing the code in the loop at least once no matter what the variable to-be-checked contains. The For loop has three parts to its intial line, an initial index value, a check for the last index value, and an incrementing algorithm. If you need to use the index after the For loop is completed, then the index variable must be set before you enter the loop. If the index is only used in the loop, then it can be declared in the loop. The outside-use index (forIndex) looks like:

int forIndex = 0;  // I always initialize my variables even if they are set in a For loop.
for (forIndex = 1; forIndex <= 5; forIndex++)
{
   // Code to execute in the for loop goes here
}

If the variable is only declared in the For Loop itself, then the variable cannot be used after the loop exits. The code for the index (forIndex) that is used only in the For loop (inside-use index):

for (int forIndex = 1; forIndex <= 5; forIndex++)
{
   // Code to execute in the for loop goes here
}

Example of the while and do loops follow. Be sure to notice when the test is done in each case. The variable must be initialized before either of these loops is invoked. In using these loops and checking for odd and even numbers, much can be accomplished. The .NET libraries needed to be included when they are needed for the code to compile and execute properly.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WhileDoLoops
{
    class Program
    {
        static void Main(string[] args)
        {
            //Declare variables, I  prefer initializing all variables.
            int whileCount = 0;
            int doCount = 0;
            char toggleChar;
            const char xChar = 'X';
            const char oChar = 'O';
            //Start the while loop to produce the eight rows
            while(whileCount < 8)
            {
                //Now start the Do loop to print out each character
                do
                {
                    //Now set character, if whileCount+doCount even then X else O
                    if ((whileCount + doCount) % 2 == 0) toggleChar = xChar; else toggleChar = oChar;
                    //Only print 8 Characters.
                    //If I do not use braces, I will put the conditional statement all on same line.
                    if (doCount < 8) Console.Write(toggleChar);
                    doCount++; // Count so all eight characters are printed.
                } while (doCount < 8); // Go through the loop one more time without printing so the X or O is set correctly.
                // Now go to the next row, be sure to reset doCount so all eight characters will be printed.
                doCount = 0;
                Console.WriteLine();
                whileCount++; // Count so all eight rows are printed.
            }
            Console.WriteLine("Pres 'Enter' to exit");
            Console.ReadLine(); //Force a read from keyboard so that I can see the results.
        }
    }
}

One key to checking for correctness of this code is to also check the automatic indent based on what you are typing. If it does not look quite right, it probably is not. Each person is different, I prefer defining my variables within the context they are needed. I do not like global variables, if I can totally avoid them. Notice when I set X and O, I make the variable a constant (const) so that I know the values will always be what I suspect they should be. The check

   if ((whileCount + doCount) % 2 == 0)

adds the two index counts and then divides by 2. If there is no remainder, the return value is 0 (or TRUE). This will cause the code that follows to be executed.

Structures, Classes, and Inheritance

Structures (structs) and Classes have many similarities, but some major differences.

  • Struct and Class can:
    1. Store variables
    2. Have { get; set; } pair for accessing variables
    3. Define a constructor
  • Items that only a Class can do
    1. Have methods, other than a constructor
    2. Inheritance
    3. Pass by reference, Structs pass by value

Being passed by reference, instead of by value, when classes are passed to another method or function any modifications to the class variables will be done to the copy of the class that was passed in. Since structs are passed by value, there is no pointer to the original struct. Instead a local copy on the stack is created. The called method only modifies the local copy and does not modified the copy that was used in the call. The easiest way to show this is to show you the results of executing actual code:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

// A namespace is a required wrapper for all C# programs. It wraps everything but the "using" statements
namespace StructsAndClasses
{
    // Declare a structure with a constructor with the same name
    public struct PersonStruct
    {
        // I prefer "wrapping" my variables so that I can do any checks when being defined (and any needed modifications going out
        // To have these methods accessed outside of this structure, you must make these access points public.
        public String FirstName { get; set; }
        public String LastName { get; set; }
        public String City { get; set; }
        // Since strings that are unitialized can cause an exception throw (at least in C++), I always initialize strings to "" to prevent a problem.
        public PersonStruct(String FN = "", String LN = "", String CT = "")
        {
            // "this." is optional, but it makes where these variables are defined explicit.
            this.FirstName = FN;
            this.LastName = LN;
            this.City = CT;
        }
    }
    // Declare a class with a constructor with the same name, same notes as for structure apply.
    public class PersonClass
    {
        public String FirstName { get; set; }
        public String LastName { get; set; }
        public String City { get; set; }
        public PersonClass(String FN = "", String LN  = "", String CT = "")
        {
            this.FirstName = FN;
            this.LastName = LN;
            this.City = CT;
        }
    }
    // Set up the Modification Functions
    public class Modifications
    {
        public void ModStruct(PersonStruct personStruct)
        {
            personStruct.FirstName = "Bob";
            personStruct.LastName = "Johnson";
            personStruct.City = "San Antonio";
            Console.WriteLine("Settings in ModStruc()");
            Console.WriteLine("First Name is: " + personStruct.FirstName + " Last Name is: " + personStruct.LastName + " City is: " + personStruct.City);
        }
        //Modify the Class
        public void ModClass(PersonClass personClass)
        {
            personClass.FirstName = "Bob";
            personClass.LastName = "Johnson";
            personClass.City = "San Antonio";
            Console.WriteLine("Settings in ModClass()");
            Console.WriteLine("First Name is: " + personClass.FirstName + " Last Name is: " + personClass.LastName + " City is: " + personClass.City);
        }
    }
    class Program
    {
        // Define the main flow for the program.
        static void Main(string[] args)
        {
            PersonStruct personStruct = new PersonStruct();
            PersonClass personClass = new PersonClass();
            Modifications mods = new Modifications(); // Bring in class that contains the two modification methods.
            personStruct.FirstName = "George";
            personStruct.LastName = "Federick";
            personStruct.City = "Santa Clara";
            Console.WriteLine("\nDo the STRUCTURE test");
            Console.WriteLine("Initial Settings");
            Console.WriteLine("First Name is: " + personStruct.FirstName + " Last Name is: " + personStruct.LastName + " City is: " + personStruct.City);
            mods.ModStruct(personStruct);
            Console.WriteLine("Final Settings");
            Console.WriteLine("First Name is: " + personStruct.FirstName + " Last Name is: " + personStruct.LastName + " City is: " + personStruct.City);

            personClass.FirstName = "George";
            personClass.LastName = "Federick";
            personClass.City = "Santa Clara";
            Console.WriteLine("\nDo the CLASS test");
            Console.WriteLine("Initial Settings");
            Console.WriteLine("First Name is: " + personClass.FirstName + " Last Name is: " + personClass.LastName + " City is: " + personClass.City);
            mods.ModClass(personClass);
            Console.WriteLine("Final Settings");
            Console.WriteLine("First Name is: " + personClass.FirstName + " Last Name is: " + personClass.LastName + " City is: " + personClass.City);
            Console.Write("Press any key to exit: ");
            Console.ReadKey();
        }
    }
}
ModClass alters main class values, ModStruct does not alter main struct values

ModClass alters main class values, ModStruct does not alter main struct values

I tried to set up the struct and the class as similar as possible. In the main program, I create an instance of the struct and of the class. I then send a copy of each to an appropriate modification method. The calls are almost identical. Because of the difference between call by value and call by reference, the struct variables are not changed in the main program, while the class variables are changed. The results would be:

Classes are the building block for Object-Oriented inheritance. There are library classes that are either “static” or dynamic. When a class is static, it means that there can be no subclasses. Some library classes can be used as a base class for a new class you are creating. In C++, I always create a child string class to properly handle NULL pointers, where a string is pointing to nothing. An empty string, defined as string foo = “”, is a safe declaration. There are two terms I will use in the rest of this introduction. Attributes are properties that can be set and retrieved, such as name, birthdate, address, etc. Methods are functions that are used to set and retrieve these attributes and functions that do whatever other processes that need to be accessed by users of this class. C# does not allow inheritance from multiple objects. The way to set up classes and subclasses is to start with the general idea and create a class describing all of the general characteristics of that object. At that point, subclasses can be created to refine the definitions of the general class so as to better describe the more specific class. For example, a Person might be a general class. It has attributes and methods that can modify the information stored about a Person. An Employee and a Student might be two different subclasses of a Person. Employees and Students would then have certain attributes and methods that better describe characteristics of each subclass. Employees might have three subclasses, Administrators, Staff, and Faculty. Employees might take care of common tasks like calculating pay. Designing the task may determine the usefulness of breaking down the Employee task into Staff and Faculty. The determination is to decide how many unique attributes and method are needed by each subclass.

Inheritance is one of the many nice features of object oriented languages. Subclasses have access to the methods and variables of the base class. They are allowed to add methods in addition to those provided by the base class. Taking the example above, I could add a Student class and a Teacher class based on the Person class. In this example, I am just adding a Student subclass that include an array of earned grades. A new class inherits from an existing class. New methods can be added to the new class. For this example, I created a Student subclass based on my PersonClass, I am adding the classes the student took, along with the grades earned, I have added a new Class for ClassGrades. The code for these two classes would look like:

    // Add class to hold grades
    public class ClassGrade
    {
        string ClassName { get; set; }
        int GradePercentage { get; set; }
        public ClassGrade(string CName, int CGrade)
        {
            ClassName = CName;
            GradePercentage = CGrade;
        }
        public void PrintGrade()
        {
            Console.WriteLine(this.ClassName + " earned grade of " + this.GradePercentage + "%");
        }
    }
    // Create a student based on the PersonClass
    public class Student : PersonClass
    {
        ArrayList classesGrades = new ArrayList();
        public void AddClass(string CName, int CGrade)
        {
            ClassGrade cGrade = new ClassGrade(CName, CGrade);
            classesGrades.Add(cGrade);
        }
        public void PrintClassGrades()
        {
            Console.WriteLine("For student " + this.FirstName + " " + this.LastName + " who lives in " + this.City);
            Console.WriteLine("  took the following classes and earned the following grades");
            foreach(ClassGrade cGrade in classesGrades)
            {
                Console.Write("  in ");
                cGrade.PrintGrade();
            }
        }
    }

The calls in main would be:

            // Set up a student, add classes and grades to an array.
            Student student = new Student();
            student.FirstName = "Tyberius";
            student.LastName = "Kirk";
            student.City = "Des Mouines";
            student.AddClass("Computer Languages", 98);
            student.AddClass("Operating Sysstems", 94);
            student.AddClass("Artificial Intelligence", 87);
            student.AddClass("C Programming", 99);
            student.AddClass("C# Programming", 94);
            Console.WriteLine("");
            student.PrintClassGrades();

The results would be:

Results from creating a student base on PersonClass and adding courses taken with grades.

Results from creating a student base on PersonClass and adding courses taken with grades.

Exceptions

If there is a problem with the execution of the code, like an index OutOfRange or a piece of hardware being unavailable, an exception is “thrown.” It is best to “catch” these exceptions and do something reasonable with the “problem.” I have found that it is best to have the code that might cause an exception to be in a “try” block, which is immediately followed by a “catch” block that handles the exception. Usually, any clean-up must be in a “finally” block that always executes. I put the try/catch/finally group in its own class method to isolate this code and be able to call it from anywhere in my project. Unfortunately, I have found that the class must be instantiated before this method can be used.

For example, to protect the user from entering the wrong date, I created a SetDate class with a SetDateNow(int year, int month, int day) method. Using exception handling can greatly reduce the size of the code. Since the System class DateTime already does a check for the validity of any given date, use its check instead of going through and checking the year, month, and day to verify that the date does exist before creating a DateTime instance.

    // Put a try/catch/finally set around a set date method.
    public class SetDate
    {
        private DateTime returnDate; // = new DateTime();
        public DateTime SetDateNow(int year, int month, int day)
        {
            // Now try to set the date, if it fails, then handle the exception.
            try
            {
                returnDate = new DateTime(year, month, day); // Accepts year. month, day, force day to be out of range
                Console.WriteLine("DateTime successfully set to " + returnDate);
            }
            catch (ArgumentOutOfRangeException outOfRange)
            {
                Console.WriteLine("Date specified is not valid.\n{0}", outOfRange.Message);
                returnDate = DateTime.Now;
                Console.WriteLine("DateTime exception,  set to " + returnDate);
            }
            finally
            {
                // Now return the results after out of the finally clause.
            }
            return returnDate;
        }
    }

I tried making a method in class Program with the Main method, but it could not be called from a class outside of Main. An example for a call from another class method to the SetDateNow() would be:

        //Modify the Class
        public void ModClass(PersonClass personClass)
        {
            SetDate setDate = new SetDate();
            personClass.BirthDate = setDate.SetDateNow(2016,3,10);
       }

An example of calling it from main would be:

            // Create the SetDate instance.
            SetDate setDate = new SetDate();
            // Set up a student, add classes and greades to an array.
            Student student = new Student();
            student.FirstName = "Tyberius";
            student.LastName = "Kirk";
            student.City = "Des Mouines";
            student.AddClass("Computer Languages", 98);
            student.AddClass("Operating Sysstems", 94);
            student.AddClass("Artificial Intelligence", 87);
            student.AddClass("C Programming", 99);
            student.AddClass("C# Programming", 94);
            Console.WriteLine("");
            student.PrintClassGrades();
            Console.WriteLine("Try causing a throw of System.ArgumentOutOfRangeException");
            student.BirthDate = setDate.SetDateNow(1985, 12, 3);
            student.BirthDate = setDate.SetDateNow(1985, 12, 32);
            student.BirthDate = setDate.SetDateNow(1985, 13, 3);
            student.BirthDate = setDate.SetDateNow(-5, 12, 3);

I performed the SetDateNow() several times to test both passing and failing calls. The output would appear as:

C# Exception (Try/Catch/Finally) handling

C# Exception (Try/Catch/Finally) handling

Tasks (including Asynchronous)

With the development of multi-Core processors, using tasks has become much more useful. The purpose of a task is to created a new thread that will execute code that is needed but does not need to go into the main process. The easiest example is performing calculations based on input from a Graphical User Interface (GUI). The GUI should not be frozen while the calculations are being performed. Therefore, these calculations are usually put into a new thread to execute while the GUI interface is freed up to accept more input. The task (usually implemented by threads) is put into “the background” to execute. The task can either run until completion and then exit, or it can perform its duties and then have some sort of way of telling the calling program its results. All tasks can throw exceptions, of which the main program will be aware.

Race Conditions

Abstract and Sealed Classes plus Virtual Methods

A standard C# Class is described above. When implemented, it can be instantiated and have sublasses inherit from it. A sealed class does not allow inheritance. Within a sealed class, all methods must be static. The sealed modifier can also be applied to methods so that a method cannot be inherited. In that case, it removes all the code that indicates a method can be inherited and is sometimes used to speed up a methods execution.

Virtual functions are similar to virtual functions in C++. The virtual modifier indicates that the inheriting class can override the inherited classes method definition. If virtual is not modifying the method, the inheriting class method can only override the inherited abstract class implementation if the new modifier is used. An example of sealed and abstract classes follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

//Namespace is always required for the creation of any project.
namespace AbstractClassDemo
{
    // If you do want a class to be inherited, used "sealed" as a class modifier
    public sealed class FindPi
    {
        // Define the one function.
        public static double pi()
        {
            return(Math.PI);
        }
    }

    // Abstract base for all shape calculations
    public abstract class ShapeCalculation
    {
        protected double DimA;
        protected double DimB;

        protected ShapeCalculation(double A, double B)
        {
            DimA = A;
            DimB = B;
        }
        //Find the area
        public double Area()
        {
            return (DimA * DimB);
        }
        //Find the perimiter
        virtual public double Perimeter()
        {
            return (2 * DimA + 2 * DimB);
        }
    }

    // Create a Rectangle based on ShapeCalulation abstract class
    public class Rectangle : ShapeCalculation
    {
        public Rectangle(double A, double B) : base(A, B) { }
        
    }

    // Create a Square based on ShapeCalulation abstract class
    public class Square : ShapeCalculation
    {
        public Square(double A) : base(A, A) { }
    }

    // Create a Circle  based on ShapeCalulation abstract class
    public class Circle : ShapeCalculation
    {
        public Circle(double A) : base(A, FindPi.pi()) { }
        public new double Area()    // We are overriding the base definition, so must say this is a "new" definition.
        {
            return (Math.Pow(DimA, 2) * DimB);
        }
        public override double Perimeter()    // We are overriding the base definition, so must say this is a "new" definition.
        {
            return (2 * DimA * DimB);
        }
    }

    // Now for the main part of the program
    class Program
    {
        static void Main(string[] args)
        {
            double A, B;
            // Do Rectangle calculations
            Console.Write("Enter Rectangle width: ");
            A = Convert.ToDouble(Console.ReadLine());
            Console.Write("Enter Rectangle heigth: ");
            B = Convert.ToDouble(Console.ReadLine());
            Rectangle rectangle = new Rectangle(A, B);
            Console.WriteLine("The Rectangle's area is: {0}", rectangle.Area());
            Console.WriteLine("The Rectangle's perimiter is: {0}", rectangle.Perimeter());

            // Do Square calculations
            Console.Write("Enter Square dimension: ");
            A = Convert.ToDouble(Console.ReadLine());
            Square square = new Square(A);
            Console.WriteLine("The Square's area is: {0}", square.Area());
            Console.WriteLine("The Square's perimiter is: {0}", square.Perimeter());

            // Do Circle calculations
            Console.Write("Enter Circle radius: ");
            A = Convert.ToDouble(Console.ReadLine());
            Circle circle = new Circle(A);
            Console.WriteLine("The Circle's area is: {0}", square.Area());
            Console.WriteLine("The Circle's perimiter is: {0}", circle.Perimeter());

            //Now have user do something before console goes away.
            Console.ReadKey();
        }
    }
}

Interface Classes

Interface classes are like templates. In some ways they are also similar to abstract classes. They cannot be instantiated but new classes can inherit from them. Even though C# does not allow inheritance from multiple classes, it does allow inheritance from multiple Interface Classes. To differentiate an Interface class from regular and abstract classes, all interface class names should start with a capital “I” followed by the descriptive name. If I added an Interface based on the program above, it would be:

    interface ColorShape
    {
        string Features();
        ShapeCalculation shape
        {
            get;
            set;
        }
        string ShapeColor
        {
            get;
            set;
        }
    } 

The inheritance would be:

     // To be added