© The Author(s), under exclusive license to APress Media, LLC, part of Springer Nature 2022
G. ByrneTarget C#https://doi.org/10.1007/978-1-4842-8619-7_13

13. Classes

Gerard Byrne1  
(1)
Belfast, Ireland
 

Classes and Objects in OOP

We learned in Chapter 12 that methods belong inside classes and classes consist of variables and methods. We saw that there are a number of different method types that can be used in our code. The method types we can create or use are
  • Void methods that return no value and simply execute code

  • Value methods that return a value of a specific data type after executing

  • Parameter methods that take actual values as their parameters and that may or may not return a value of a specific data type after executing

  • Overloaded methods, which are methods with the same name but different parameters

There are many methods used in our code, which are not written by us, for example, WriteLine(), Write(), ReadLine(), ToDouble(), ToInt32(), and ToDateTime(). The methods we have created and the methods we have not created but have used all have one thing in common:

They all live inside a class; they are part of a class.

It is the commonality of classes that this chapter will be concentrating on. The crucial takeaway from the last chapter and a vital thing to remember in this chapter is that a class contains
  • Methods

  • Variables

When we create our own classes, they act in the same way as the classes in .NET or any other classes in that they can be reused, usually by creating instances of them, to create one or more objects.

A Class Is a Data Structure

In the software development world, there are many programming languages and many different types of program. Some languages and programs are what can be called legacy languages and legacy programs . COBOL is one such legacy programming language, but it is still a very powerful language that widely exists in many commercial applications. On the other hand, other languages are popular and use the latest methods or features in object-oriented programming (OOP). With traditional languages like COBOL, developers often coded the programs as a set of instructions that followed a sequence, and hence it was called sequential programming . With object-oriented programming (OOP) , there is now a focus on structuring the code more and using objects. This is achieved by organizing or capturing the code in logically related methods and data objects called classes. This process of organizing or capturing the data and methods is called encapsulation .1

Our classes will contain fields, and sometimes these fields, as we have read before, can be referred to as members or variables or properties or instance variables. For simplicity we should just think of them as variables. In this chapter we are now going to elaborate on what can be held within a class, and we can categorize these as either:
  • Data members that store data associated with the class or data associated with an instance of the class, the object. We can simply think of them as a variable if they are private or protected and as a field if they are public.

  • Function members that are used to execute code. They are the methods we use to hold our code.

In a class we can have different types, and when trying to learn about classes and objects, it is very important that we understand what the types are and what their role is, so we will look at these in more detail now.

Type 1: Fields

A field is a variable of any data type that is declared directly in our class. A field will usually store data that needs to be accessible to more than one method in the class and must be stored for longer than the lifetime of any single method. In relation to some of the examples we have used so far, we have had:
  • A class called QuoteArithmetic that held details about an insurance quote and had fields that represented the
    • Age of the vehicle in terms of years. It was called vehicleAgeInYears.

    • Current mileage of the vehicle. It was called vehicleCurrentMileage.

  • A class called MethodsV1 that held details about an insurance claim and had fields that represented the
    • id of the repair shop making the claim. It was called repairShopID.

    • Claim amount. It was called claimAmount.

When we declare these fields at the class level, they can be used by more than one method of our class. The variables are said to have a class scope within the class. On the other hand, when the field will be used by only one method within the class, we should ensure that the variable is declared inside the method, and therefore it is said to have a method scope. A field is declared within the class block by identifying
  • The access level of the field, for example, public or private

  • The type of the field, for example, double, string, etc.

  • The name of the field, for example, premium

Examples of the fields are shown in Tables 13-1 and 13-2.
Table 13-1

A class with a public field

Example

Explanation

public class QuoteArithmetic

{

  public int vehicleAgeInYears;

}

Access modifier is public.

Type is int.

Name is vehicleAgeInYears.

Table 13-2

A class with a private field

Example

Explanation

public class MethodsV1

{

  private String repairShopID;

}

Access modifier is private.

Type is String.

Name is repairShopID.

Type 2: Constants

The value of a variable can change throughout the lifetime of the application. In C# when a variable is declared using the const keyword, the value cannot be modified. In essence, it is a constant value, and a constant value will therefore not change during the lifetime of the application and is always known to the compiler at runtime. A constant is declared within the class block by
  • Identifying the access level of the field, for example, public or private.

  • Adding the const modifier.

  • Identifying the type of the field, for example, double, String, etc.

  • Identifying the name of the field. In C# the naming convention may be to use PascalCase for class names, method names, and constants or readonly variables, whereas in Java the naming convention could be to use capital letters for the name of a constant, for example, BASEINSURANCEAMOUNT. Ultimately it is a convention, rather than a must-do.

  • Setting its fixed value.

Examples of constant values are shown in Tables 13-3 and 13-4.
Table 13-3

A class with a constant field with public access

Example

Explanation

public class QuoteArithmetic

{

  public const int maximumDriverAge=100;

}

Access modifier is public.

Modifier const makes it a constant value.

Type is int.

Name is maximumDriverAge.

Value is fixed to 100.

Table 13-4

A class with a constant field with private access

Example

Explanation

public class MethodsV1

{

  private const double minimumQuote=100.00;

}

Access modifier is private.

Modifier const makes it a constant value.

Type is double.

Name is minimumQuote.

Value is fixed at 100.00.

Type 3: Methods

Methods form a large part of the C# language. Our C# application will start its execution from within the Main() method, so in our code the Main() method will exist in one of our classes and forms the entry point for the application being developed. As developers we use methods to modularize our code and make it easier to read and maintain. More importantly, methods form the basis for the vitally important concept of Test-Driven Development (TDD), where the idea is to test a unit of code, which is usually a method. In Test-Driven Development we write tests first before we write our classes and methods – yes, that is strange. With Test-Driven Development the tests themselves are methods, which are inside a class, called the test class. So once again we see the importance of classes with methods and variables.

When we create methods, we are really developing blocks of code that perform an action, and we can say that methods hold our business logic. A method is declared within the class block by identifying
  • The access level of the method

  • Optional modifiers such as abstract, sealed, static, override, and virtual

  • The return type of the method

  • The name of the method

  • Any parameters that are passed into the method

// Method 1
public static void HowManyClaimsAreBeingMade()
{
  /*
  Read the user input for the number of claims being made
  and convert the string value to an integer data type*/
  Console.WriteLine("How many claims are being made? ");
  numberOfClaimsBeingMade = Convert.ToInt32(Console.ReadLine());
} // End of HowManyClaimsAreBeingMade() method
Listing 13-1

Example method code snippet

Analysis of the Method Code in Listing 13-1
  • Access level of the method is public.

  • The static modifier has been applied to the method, and we will learn more about static in this chapter.

  • The return type of the method is void – it does not return anything.

  • The name of the method is HowManyClaimsAreBeingMade.

  • No parameters are passed into the method – it is parameterless.

Type 4: Properties

As we saw in Tables 13-1, 13-2, 13-3, and 13-4, it is possible to set the field access modifier as public or private. Private fields are referred to as variables and public fields are referred to as fields. The reason for setting the field as private is to ensure that it cannot be accessed directly from outside the class, by another class. We may therefore wonder how we can read the value of a variable or write a value to a variable from outside its class if it is set as private. Well, the answer is by using a property, which is a mechanism that allows for reading and writing, getting or setting, of the variable.

Properties are declared in the class block by specifying the access level of the variable, followed by the type of the property, followed by the name of the property, and followed by a code block that can declare a get accessor and/or a set accessor.
  • Get accessor, getter

A get accessor method used to read the value of a private field is called a getter . The method is used to return a value to outside classes; it is a read method and the method will be used as shown in Listing 13-2.
public class Methods
{
  double totalOfAllClaims;
  public double TotalOfAllClaims
  {
    get
    {
      return totalOfAllClaims;
    }
  }
} //End of class
Listing 13-2

Example code snippet for a getter

So, in essence, the getter method gets the value of a field, variable, and returns the value to the calling statement. In Listing 13-2 we can see that the getter is used to get the value of the field totalOfAllClaims. The get accessor returns this value to the statement that calls it.
  • Set accessor, setter

A set accessor method used to write a value to a private field is called a setter . The method is used to accept a value from outside the class and the method will be used as shown in Listing 13-3.
public class Methods
{
  double totalOfAllClaims;
  public double TotalOfAllClaims
  {
    get
    {
      return totalOfAllClaims;
    }
    set
    {
       totalOfAllClaims = value;
    }
  }
} //End of class
Listing 13-3

Example code snippet for a setter

So, in essence, the setter method sets the value of a field. In Listing 13-3 we can see that the setter is used to set the value of the field totalOfAllClaims. The set accessor assigns the new value to the field.

Type 5: Constructor

We now know that fields with an access modifier of private can have their value amended using a setter. There is also a very special method that can exist in a class and can be used for the purpose of initializing the values of the fields or writing some code. This special method is called a constructor and will be created by the developer.

Default Constructor

If we do not want to initialize the fields, they will have the default value for the data type of the particular field, for example, the int data type has a default of 0 and the double data type has a default of 0.00. When we choose not to develop a constructor and therefore leave the default values for the fields, there is still a constructor in the class; it is called a default constructor and it will not be visible.

Analysis of the Constructor Code in Figure 13-1
  • Here we have created an instance of the class MethodsV1 – we are instantiating the class.

  • This instantiation passes in no values, arguments, to the class called MethodsV1, as there are no values between the open and close brackets ().

  • This means that the default constructor has been used and the fields of the class will have the default value for their data type.

An 8-line code exhibits the use of open and close parentheses to instantiate the new Methods V 1 class.

Figure 13-1

Instantiate the class using the default constructor , no values

Custom Constructor

If we want to initialize the fields so they do not have their default values, we need to create our own constructor. Once we create our own constructor method, the default constructor no longer exists, but we could still manually add a default constructor. Figure 13-2 shows the custom constructor.

A 13-line code exhibits the use of no return type and custom constructor parameters, namely, repair Shop I d type string and claim Amount type double.

Figure 13-2

Creating the custom constructor

The constructor “method” is used to initialize the value of the fields in the class. It may be used to initialize all the fields or just some of them. A constructor has the following features (we will refer to Figure 13-2):
  • It must have the same name as the class – in this example it is MethodsV1.

  • It must have an access modifier of public.

  • It has no return type, not even void.

  • It has parameters, and they are of the same type as the fields that are to be initialized. Here we have a string followed by a double.

The constructor, method, is “activated” when the class is created. We will see more about this as we code the examples in this chapter. The way a class is “activated” is by creating an instance of the class. The reason we use an instance of the class is because the class itself is a template and should not be used directly.

In the code shown in Figure 13-2, we could have used the keyword this to refer to the fields of the class, and we would do this to differentiate between the field of the class and the parameter of the method. But wait a minute! Could we not have named the parameters of the method different from the field names of the class and then avoided using the this keyword? Yes, of course we could, but in terms of clean code and convention, using the same name for the variables can be seen as preferential, and therefore we use the this keyword. We can think of this as referring to the current object, the field of the class we are in.

Analysis of the Constructor Code in Figure 13-3
  • This instantiation passes in two values, arguments, to the constructor of the MethodsV1 class.

  • As we can see from the two values between the open and close brackets (), we are passing in one string, “RS1234”, followed by one double, 2999.50, to the constructor of the class called MethodsV1.

  • The values, arguments, are passed to the constructor, which has been created, and the constructor accepts these arguments as its parameters.

  • The values are of types string and double in this specific order.

  • Remember, the default constructor accepts no values.

  • Since we are using a custom constructor, we know that the default constructor does not exist.

An 8-line code exhibits the Methods V 1 class, my Instance Of Methods V 1 instance, and quoted R S 1234, 299.50 arguments of the custom constructor.

Figure 13-3

Instantiate the class using a custom constructor, values passed .

The class code to go with this instantiation could be as shown in Figure 13-2 and reproduced here as Listing 13-4.
public class MethodsV1
{
  String repairShopId;
  double claimAmount;
  public MethodsV1(string repairShopId, double claimAmount)
  {
    this.repairShopId = repairShopId;
    this.claimAmount = claimAmount;
  } // End of constructor
} // End of class
Listing 13-4

Class with custom constructor

Analysis of the Constructor Code in Listing 13-4 and Figure 13-3
  • Figure 13-3 shows that when the class is instantiated, the first argument is the value “RS1234”.

  • This argument is accepted by the repairShopId parameter, as in Listing 13-4, and the default value of the repairShopId field is overwritten. The value becomes “RS1234”.

  • Figure 13-3 shows that when the class is instantiated, the second argument is the value 2999.50.

  • This argument is accepted by the claimAmount parameter, as in Listing 13-4, and the default value of the claimAmount field is overwritten. The value becomes 2999.50.

  • The constructor, as in Listing 13-4, therefore uses the arguments passed to it to initialize the fields.

  • this.repairShopId, in Listing 13-4, refers to the field repairShopID of the class.

  • The field repairShopID, in Listing 13-4, is therefore assigned the value “RS1234”.

  • this.claimAmount, in Listing 13-4, refers to the field claimAmount of the class.

  • The field claimAmount, in Listing 13-4, is therefore assigned the value 2999.50.

Since there is a constructor method in this example, it means that the default constructor no longer exists – it has been overwritten.

Constructor Overloading

In C# it is possible to use overloading of constructors, and the concept of overloading constructors is the same as the method overloading that exists in the C# language, which we looked at in the previous chapter. Overloading means that it is possible for us to have constructors with the same name, the name of the class, but which take a different set of input parameters. This is comparable to the overloading of methods that we looked at in the last chapter. Listing 13-5 shows code where we have three constructors. The first constructor has two parameters of type string followed by a double. The second constructor has only one parameter of type string. The third constructor has only one parameter of type double. Remember a constructor has the same name as the class, so all three constructors are called MethodsV1 . Constructors also have no return type.
public class MethodsV1
{
 String repairShopId;
 double claimAmount;
 public MethodsV1(string repairShopId, double claimAmount)
 {
   this.repairShopId = repairShopId;
   this.claimAmount = claimAmount;
 }// End of constructor with parameters of type String and double
 public MethodsV1(string repairShopId)
 {
   this.repairShopId = repairShopId;
 }// End of constructor with a parameter of type String
public MethodsV1(double claimAmount)
 {
   this.claimAmount = claimAmount;
 }// End of constructor with a parameter of type double
} // End of class MethodsV1
Listing 13-5

Constructor overloading more than one custom constructor

As we read earlier, many commercial programs will involve large amounts of code, and from a maintenance and testing perspective, it is essential that the program has a good structure. Well-written and organized programs allow those who maintain or test them to
  • Follow the code and the flow of events easier.

  • Find things quicker.

Let’s recap what we have seen in Chapter 12 :

To structure the program code better, we could break the code into small functional parts, each part performing one task. When we have a functional part, which does one particular thing, it may be possible for that functional part to be used by other parts of the program.

In the last chapter on methods, we created methods that performed one task, and then the methods were called as required. Well, this section will develop this concept even further.

Suppose we have developed a program with the following methods :
  • AgentCommission()

  • AgentBonus()

  • CustomerPersonalDetails()

  • CustomerVehicleDetails()

Suppose all the methods are inside a class and outside the Main() method. Now, this would be fine, and the code could work, and it’s similar to what we did when coding in Chapter 12. But, looking closely at the method names, we might suggest that they relate to two distinct categories or groups , an Agent and a Customer.

If this is the case, we should think, Would it not be better if each method was placed inside a class that related to its category? This would mean that our code could now look something like the three classes shown in Listings 13-6, 13-7, and 13-8.

Class 1

The class in Listing 13-6 is the main entry point into the application and is used to start the program as it has the Main() method .
public class Insurance
{
  public static void Main(String[] args)
  {
    //Some code to call the methods in the other class(es)
  } // End of Main() method
} // End of Insurance class
Listing 13-6

Class with the Main() entry point

Class 2

The class in Listing 13-7 has the methods and fields associated with an Agent; it does not have a Main() method as only one class in our application can have the entry point.
public class Agent
{
  public static void AgentCommission()
  {
    //Some business logic code to calculate the commission
  } // End of AgentCommission method
  public static void AgentBonus()
  {
    //Some business logic code to calculate the bonus
  }// End of AgentBonus method
}// End of Agent class
Listing 13-7

Class for the Agent

Class 3

This class in Listing 13-8 has the methods and fields associated with a Customer; it does not have a Main() method as only one class in our application can have the entry point.
public class Customer
{
  public static void CustomerPersonalDetails()
  {
      //Some code to read in the customer personal details
  }// End of CustomerPersonalDetails method
  public static void CustomerVehicleDetails()
  {
      //Some code to read in the customers vehicle details
  }// End of CustomerVehicleDetails method
}// End of Customer class
Listing 13-8

Class for the Customer

Our code is now organized into classes and into methods within the classes. More importantly, the distinct classes hold methods and fields that have a similar purpose. This is a good starting point, and we might, even at this stage, think we could have completed the separation process in a different way. We could, and that is part of the “joy” of programming, as developers think in different ways, and no one way is the right way.

While coding the examples in each of the previous chapters, we have seen at least one property of a class, and we have used methods that belonged to different classes. Listing 13-9 shows the Length property of the Arrays class, and we should notice that the Length property does not contain the opening and closing parentheses () – it is not a method.
for (int counter = 0; counter < employeeAndSalary.Length; counter++)
{
  Console.WriteLine($"The element positioned at {counter} is {^(employeeAndSalary.Length - (counter))} from the end of the array");
}
Listing 13-9

Length property of the Arrays class

Listing 13-10 shows the Parse() method of the Int32 class, and we should notice that the method does contain the opening and closing parentheses () – it is a method.
    return Int32.Parse(Console.ReadLine());
Listing 13-10

Parse method of the Int32 class also the ReadLine() method

When using the method called Parse(), some things to note are as follows:
  • When the line of code in Listing 13-10 is entered into the Integrated Development Environment (IDE) and the full stop is typed after the word Int32, a pop-up window appears.

  • The pop-up window displays the methods and fields that are part of the Int32 class.

  • The methods have the cube icon.

  • The fields have the spanner icon, but there are no fields for Parse.

  • The constants have the rectangle with lines icon.

  • However, some Integrated Development Environments use the symbols M for a method and F for a field.

  • The Int32 class has only methods that are associated with 32-bit integers.

In Figure 13-4 we can see the methods, in particular the Parse() method. We can also see that the Int32 class has methods and constants – it has no fields.

A pop-up window highlights the Parse method among the options with icons for I n t 32 class constants and methods. The dot notation after I n t 32 is highlighted in the code.

Figure 13-4

Int32 class with its methods and constants

double answer = Math.Sqrt(9.00);
Listing 13-11

Sqrt() method from the Math class

In Listing 13-11 we have used the method called Sqrt(), which belongs to the class called Math :
  • When the code in Listing 13-11 is entered into the Integrated Development Environment (IDE) and the full stop is typed after the word Math, a pop-up window appears.

  • The pop-up window displays any methods and fields that are part of the Math class.

  • The methods have the cube icon.

  • The fields would have the spanner icon, but Math has no fields.

  • The constants have the rectangle with the lines, for example, PI and Tau.

  • The Math class has only methods that are associated with mathematics.

In Figure 13-5 we can see the methods, cube icon, in particular the Sqrt() method that accepts a double as an argument.

A pop-up window highlights the S q r t method among the options with icons for Math class constants and I n t 32 class methods. The dot notation after Math class is highlighted in the code.

Figure 13-5

Math class with its methods

Great, now we can think of methods that come with C# and from the imports, not just being coded in one class but in numerous classes. With these classes there is a high degree of code separation . We call it separation of concern (SoC), where associated methods are kept together, and this is what we can do – we have done this in Chapter 12. Think about separation of concern using these real-world examples.

In a school there are different roles :
  • The head teacher

  • The senior teachers

  • The teachers

  • The administration staff

  • The facilities staff

  • The canteen staff

All roles have separate concerns, but all concerns serve one purpose, to keep the school working.

In a hospital there are different roles:
  • The consultants

  • The doctors

  • The nurses

  • The care assistants

  • The administration staff

  • The facilities staff

  • The catering staff

All roles have separate concerns, but all concerns serve one purpose, to keep the hospital functioning.

Let's code some C# and build our programming muscle.

Now it is time for us to code some classes with methods and show the separation of concern working in our application. We will be programming the same application that we have just completed in Chapter 12, so we can choose to copy and paste code as required, but the following instructions assume that we are starting again with no code.

Add a new project to hold the code for this chapter.
  1. 1.

    Right-click the solution CoreCSharp.

     
  2. 2.

    Choose Add.

     
  3. 3.

    Choose New Project.

     
  4. 4.

    Choose Console App from the listed templates that appear.

     
  5. 5.

    Click the Next button.

     
  6. 6.

    Name the project Chapter13 and leave it in the same location.

     
  7. 7.

    Click the Next button.

     
  8. 8.

    Choose the framework to be used, which in our projects will be .NET 6.0 or higher.

     
  9. 9.

    Click the Create button.

     
Now we should see the Chapter13 project within the solution called CoreCSharp .
  1. 10.

    Right-click the project Chapter13 in the Solution Explorer panel.

     
  2. 11.

    Click the Set as Startup Project option.

     
Notice how the Chapter13 project name has been made to have bold text, indicating that it is the new startup project and that it is the Program.cs file within it that will be executed when we run the debugging.
  1. 12.

    Right-click the Program.cs file in the Solution Explorer window.

     
  2. 13.

    Choose Rename.

     
  3. 14.

    Change the name to ClaimApplication.cs.

     
  4. 15.

    Press the Enter key.

     
  5. 16.

    Double-click the ClaimApplication.cs file to open it in the editor window.

     
Now we can set up the code structure with a namespace, and inside it will be the ClaimApplication class, and inside the class will be the Main() method. The shortcut for creating the Main() method is to type svm and press the Tab key twice.
  1. 17.

    In the editor window, add the code in Listing 13-12.

     
namespace Chapter13
{
  internal class ClaimApplication
  {
    static void Main(string[] args)
    {
    } // End of Main() method
  } // End of ClaimApplication class
} // End of Chapter13 namespace
Listing 13-12

Class with the Main() method

Now we have a class with a Main() method. We can follow points 18–21 in the following to set it as the Startup object, but as this is the only class with a Main() method in this startup project, it will automatically be used as the Startup object.
  1. 18.

    Right-click the Chapter13 project in the Solution Explorer panel.

     
  2. 19.

    Choose Properties from the pop-up menu.

     
  3. 20.

    Choose the Chapter13.ClaimApplication class in the Startup object drop-down list.

     
  4. 21.

    Close the Properties window.

     
Add the ClaimDetails class , which has no Main() method.
  1. 22.

    Right-click the Chapter13 project in the Solution Explorer window.

     
  2. 23.

    Choose Add.

     
  3. 24.

    Choose New Item.

     
  4. 25.

    Choose Class.

     
  5. 26.

    Change the name to ClaimDetails.cs.

     
  6. 27.

    Click the Add button.

     
The ClaimDetails class code will appear in the editor window and will be similar to Listing 13-13.
namespace Chapter13
{
  internal class ClaimDetails
  {
  }  // End of ClaimDetails class
}  // End of Chapter13 namespace
Listing 13-13

ClaimDetails class with no Main() method

We are now going to use the same code, with some small changes, that we created for the MethodsValue program, but the methods will be contained within the ClaimDetails class and will be called from within the ClaimApplication class, which contains the Main() method. This will now ensure that we have some degree of separation. Remember that the methods were numbered, so the following instructions will reference the methods by their number. We will then code further classes to reinforce the concept of classes and objects.
  1. 28.

    Amend the code, as in Listing 13-14, to create the required class-level variable.

     
namespace Chapter13
{
  internal class ClaimDetails
  {
    int numberOfClaimsEntered;
  }  // End of ClaimDetails class
}  // End of Chapter13 namespace
Listing 13-14

Add the class-level variable

REMEMBER

We have the code for the methods in the MethodsValue.cs class , so copy and paste and remove the static keyword.
  1. 29.

    Amend the ClaimDetails code, as in Listing 13-15, to add method 1. Notice that static has been removed.

     
  internal class ClaimDetails
  {
    int numberOfClaimsBeingMade;
    /******************* METHOD ONE ******************/
    public int HowManyClaimsAreBeingMade()
    {
      /*
      Read the user input for the number of claims being made
      and convert the string value to an integer data type
      */
      Console.WriteLine("How many claims are being made? ");
      return Convert.ToInt32(Console.ReadLine());
    } // End of HowManyClaimsAreBeingMade() method
  }  // End of ClaimDetails class
Listing 13-15

Add method 1

  1. 30.

    Click the File menu.

     
  2. 31.

    Choose Save All.

     
Now that we have the method, we should be able to refer to it from the other class called ClaimApplication. We should take note that the full name of the method will have to contain the class name, but as we said earlier, to use the ClaimDetails class, we make an instance of it. We do not use the original class as it is the template. We will therefore create an instance of the class from within the Main() method of the ClaimApplication class .
  1. 32.

    Amend the ClaimApplication class, as in Listing 13-16, to create an instance of the ClaimDetails class.

     
  internal class ClaimApplication
  {
    static void Main(string[] args)
    {
      ClaimDetails myClaimDetailsInstance = new ClaimDetails();
    } // End of Main() method
  } // End of ClaimApplication class
Listing 13-16

Create an instance of the ClaimDetails class

  1. 33.

    Amend the Main() method to call the HowManyClaimsAreBeingMade() method , method 1, and assign it to the numberOfClaimsBeingMade variable, as in Listing 13-17.

     
    static void Main(string[] args)
    {
      ClaimDetails myClaimDetailsInstance = new ClaimDetails();
      int numberOfClaimsBeingMade = myClaimDetailsInstance.HowManyClaimsAreBeingMade();
    } // End of Main() method
Listing 13-17

Call the HowManyClaimsAreBeingMade() method

This clearly shows the concept of classes:
  • A class without a Main() method has been created to hold methods and fields.

  • From another class, which has a Main() method, an instance of the class containing the methods is created.

  • Using the instance of the class, we have access to the methods and fields of the class that have the public access modifier and are not static, that is, they belong to the instance of the class, not the class itself.

  • Adding the full stop after the instance name means those methods and fields that are accessible will be displayed. This is called the dot notation.

This means that we could create as many methods as we like in the class and create as many classes as we like. This idea of separating our code into methods and our methods into classes is exactly what a C# application should look like when it is being coded.

Let us just emphasize a few points that are crucial if we are to fully understand and use classes and objects :
  • The word static in front of a method or field of a class means that the method or field belongs to the class it is declared in.

  • When we make an instance of the class, we will not be able to access the static fields or the static methods using the instance name.

  • Static fields and methods are available directly inside the class they are declared in.

  • To access a static field or a static method, we use the class name, not the name of the instance of the class.

A two-part window exhibits the failed my Instance Of Example Static lines on the right side from the static i n t and static void lines on the left side.

Figure 13-6

Static fields and methods not accessible from a class instance

Now check that the method is being read correctly.
  1. 34.

    Click the File menu.

     
  2. 35.

    Choose Save All.

     
  3. 36.

    Click the Debug menu.

     
  4. 37.

    Choose Start Without Debugging.

     
The console window will appear, as shown in Figure 13-7, and ask the user to input the number of claims to be made. The method from the class without the Main() method has been called from the class with the Main() method.
  1. 38.

    Type 2 and press the Enter key.

     
  2. 39.

    Press the Enter key.

     

A console window depicts 2 as the number of claims to be made. Below is a C colon address followed by an instruction to close the window.

Figure 13-7

Method called from another class

This is excellent! Our method has been called from another class. We will now add more fields and methods to the ClaimDetails class.
  1. 40.

    Amend the ClaimDetails class, as in Listing 13-18, to add the additional fields we require and initialize the existing variable to 0.

     
namespace Chapter13
{
  internal class ClaimDetails
  {
    int numberOfClaimsEntered = 0;
    static int arrayPositionCounter = 0;
    /*
   The array is going to hold the data for 2 claims.
   Each claim has four pieces of information. The number of
   data items is therefore 2 multiplied by 4 = 8.
   So, we will make the array for this example of size 8.
   Not the best way to do things but fine for now.
   */
    static string[] repairShopClaims = new string[8];
    /******************* METHOD ONE ******************/
    public int HowManyClaimsAreBeingMade()
    {
Listing 13-18

Add the additional class-level variables and array we will use

  1. 41.

    Amend the ClaimDetails code , as in Listing 13-19, to add method 2 after method 1. Notice that static has been removed.

     
    /******************* METHOD TWO ******************/
    public void CurrentValueOfCounter()
    {
      Console.WriteLine("The current value of the counter is :" + numberOfClaimsEntered + " ");
    } // End of CurrentValueOfCounter() method
  }  // End of ClaimDetails class
}  // End of Chapter13 namespace
Listing 13-19

Add method 2

  1. 42.

    Amend the ClaimDetails code, as in Listing 13-20, to add method 3 after method 2. Notice that static has been removed.

     
    /******************* METHOD THREE ******************/
    public string ReadTheRepairShopId()
    {
      Console.WriteLine("What is your repair shop id? ");
      return Console.ReadLine();
    }// End of ReadTheRepairShopId() method
  }  // End of ClaimDetails class
}  // End of Chapter13 namespace
Listing 13-20

Add method 3

  1. 43.

    Amend the ClaimDetails code , as in Listing 13-21, to add method 4 after method 3. Notice that static has been removed.

     
    /******************* METHOD FOUR ******************/
    public void WriteRepairShopIdToTheArray(string repairShopId)
    {
      repairShopClaims[arrayPositionCounter] = repairShopId;
      arrayPositionCounter++;
    } // End of WriteRepairShopIdToTheArray() method
  }  // End of ClaimDetails class
}  // End of Chapter13 namespace
Listing 13-21

Add method 4

  1. 44.

    Amend the ClaimDetails code, as in Listing 13-22, to add method 5 after method 4. Notice that static has been removed.

     
    /******************* METHOD FIVE ******************/
    public string ReadTheVehiclePolicyNumber()
    {
      Console.WriteLine("What is the vehicle policy number? ");
      return Console.ReadLine();
    } // End of ReadTheVehiclePolicyNumber() method
  }  // End of ClaimDetails class
}  // End of Chapter13 namespace
Listing 13-22

Add method 5

  1. 45.

    Amend the ClaimDetails code , as in Listing 13-23, to add method 6 after method 5. Notice that static has been removed.

     
    /******************* METHOD SIX ******************/
    public void WriteVehiclePolicyNumberToTheArray(string vehiclePolicyNumber)
    {
      repairShopClaims[arrayPositionCounter] = vehiclePolicyNumber;
      arrayPositionCounter++;
    } // End of WriteVehiclePolicyNumberToTheArray() method
  }  // End of ClaimDetails class
}  // End of Chapter13 namespace
Listing 13-23

Add method 6

  1. 46.

    Amend the ClaimDetails code, as in Listing 13-24, to add method 7 after method 6. Notice that static has been removed.

     
    /******************* METHOD SEVEN ******************/
    public double ReadTheAmountBeingClaimed()
    {
      Console.WriteLine("What is the amount being claimed for the repair? ");
      return Convert.ToDouble(Console.ReadLine());
    } // End of ReadTheAmountBeingClaimed() method
  }  // End of ClaimDetails class
}  // End of Chapter13 namespace
Listing 13-24

Add method 7

  1. 47.

    Amend the ClaimDetails code , as in Listing 13-25, to add method 8 after method 7. Notice that static has been removed.

     
    /******************* METHOD EIGHT ******************/
    public void WriteClaimAmountToTheArray(double claimAmount)
    {
      repairShopClaims[arrayPositionCounter] = claimAmount.ToString();
      arrayPositionCounter++;
    } // End of WriteClaimAmountToTheArray() method
  }  // End of ClaimDetails class
}  // End of Chapter13 namespace
Listing 13-25

Add method 8

  1. 48.

    Amend the ClaimDetails code, as in Listing 13-26, to add method 9 after method 8. Notice that static has been removed.

     
    /******************* METHOD NINE ******************/
    public DateTime ReadTheRepairDate()
    {
      Console.WriteLine("What was the date of the repair? ");
      return Convert.ToDateTime(Console.ReadLine());
    }// End of method ReadTheRepairDate() method
  }  // End of ClaimDetails class
}  // End of Chapter13 namespace
Listing 13-26

Add method 9

  1. 49.

    Amend the ClaimDetails code, as in Listing 13-27, to add method 10 after method 9. Notice that static has been removed.

     
    /******************* METHOD TEN ******************/
    public void WriteRepairDateToTheArray(DateTime claimDate)
    {
      repairShopClaims[arrayPositionCounter] = claimDate.ToString();
      arrayPositionCounter++;
    } // End of method WriteRepairDateToTheArray() method
}  // End of ClaimDetails class
}  // End of Chapter13 namespace
Listing 13-27

Add method 10

  1. 50.

    Amend the ClaimDetails code , as in Listing 13-28, to add method 11 after method 10. Notice that static has been removed.

     
    /******************* METHOD ELEVEN ******************/
    public void DisplayAllItemsInTheArray()
    {
      foreach (var itemInTheClaimsArray in repairShopClaims)
      {
        Console.WriteLine("The item in the array is: " + itemInTheClaimsArray + " ");
      }
    } // End of method DisplayAllItemsInTheArray()
  }  // End of ClaimDetails class
}  // End of Chapter13 namespace
Listing 13-28

Add method 11

  1. 51.

    Amend the ClaimDetails code, as in Listing 13-29, to add method 12 after method 11. Notice that static has been removed.

     
    /******************* METHOD TWELVE ******************/
    public double AccumulateClaimAmount(double
    claimAmountPassedIn, double totalOfAllClaims)
    {
      totalOfAllClaims += claimAmountPassedIn;
      return totalOfAllClaims;
    }// End of method AccumulateClaimAmount()
  }  // End of ClaimDetails class
}  // End of Chapter13 namespace
Listing 13-29

Add method twelve

  1. 52.

    Amend the ClaimDetails code , as in Listing 13-30, to add method 13 after method 12. Notice that static has been removed.

     
   /******************* METHOD THIRTEEN ******************/
    public double DetermineVATAmount(double totalValueOfClaimsPassedIn, double vatAmount)
    {
      vatAmount = totalValueOfClaimsPassedIn - (totalValueOfClaimsPassedIn / 1.20);
      return vatAmount;
    } // End of method DetermineVATAmount()
  }  // End of ClaimDetails class
}  // End of Chapter13 namespace
Listing 13-30

Add method 13

  1. 53.

    Amend the ClaimDetails code, as in Listing 13-31, to add method 14 after method 13. Notice that static has been removed.

     
    /******************* METHOD FOURTEEN ******************/
    public void DisplayInvoiceReceipt(double
           totalValueOfClaimsPassedIn, double vatPassedIn)
    {
      Console.WriteLine(" Invoice for vehicle repairs ");
      Console.WriteLine("Nett claim " + (totalValueOfClaimsPassedIn - vatPassedIn) + " ");
      Console.WriteLine("VAT amount " + vatPassedIn + " ");
      Console.WriteLine("Total amount " + totalValueOfClaimsPassedIn + " ");
    } // End of method DisplayInvoiceReceipt()
  }  // End of ClaimDetails class
}  // End of Chapter13 namespace
Listing 13-31

Add method 14

  1. 54.

    Amend the ClaimDetails code , as in Listing 13-32, to add method 15 after method 14. Notice that static has been removed.

     
    /******************* METHOD FIFTEEN ******************/
    public void DisplayInvoiceReceipt(double
    totalValueOfClaimsPassedIn, double vatPassedIn, string
    messagePassedIn)
    {
      Console.WriteLine("********************************");
      Console.WriteLine(" Invoice for vehicle repairs ");
      Console.WriteLine("Nett claim " + (totalValueOfClaimsPassedIn - vatPassedIn) + " ");
      Console.WriteLine("VAT amount " + vatPassedIn + " ");
      Console.WriteLine("Total amount " + totalValueOfClaimsPassedIn + " ");
      Console.WriteLine(messagePassedIn);
      Console.WriteLine("********************************");
    } // End of method DisplayInvoiceReceipt
}  // End of ClaimDetails class
}  // End of Chapter13 namespace
Listing 13-32

Add method 15

Code Analysis

Now, let’s stop and think what we have just done:
  • We have created a new class without a Main() method it is called ClaimDetails.

  • We have added the fields that we will use in the methods of the class.

  • We have added the original methods we had in the MethodsValue class in the last chapter.

  • We have created a class called ClaimApplication with a Main() method.

  • In the Main() method we have
    • Created an instance of the ClaimDetails class

    • Accessed the method called HowManyClaimsAreBeingMade() by using the name of the class instance we created, followed by a full stop (dot notation), and then selecting the method

We will now continue with the code in the ClaimApplication class .
  1. 55.

    Amend the code, as in Listing 13-33, in the ClaimApplication class, to add the rest of the fields we will need in this class.

     
    static void Main(string[] args)
    {
      double vatAmount = 0.00, totalOfAllClaims = 0.00;
      ClaimDetails myClaimDetailsInstance = new ClaimDetails();
      int numberOfClaimsBeingMade
        = myClaimDetailsInstance.HowManyClaimsAreBeingMade();
    } // End of Main() method
Listing 13-33

Add the two additional fields we need in the Main() method class

  1. 56.

    Now add the do while loop within the Main() method, as in Listing 13-34.

     
      int numberOfClaimsBeingMade
        = myClaimDetailsInstance.HowManyClaimsAreBeingMade();
      /*
      As we are using a variable in the loop our code is
      flexible and can be used for any number of claims.
      An ideal situation and good code.
      */
      do
      {
      } while (numberOfClaimsEntered < numberOfClaimsBeingMade);
    } // End of Main() method
Listing 13-34

Add the do while construct

Now we will call the method that will read the repair shop id, remembering that the method does not exist in the class we are in. We will need to call it using the instance of the class that we created, myClaimDetailsInstance. Remember, after we enter the instance name and type the dot, the list of fields and methods of the class will appear if they are accessible, so we should select the method rather than typing it.

If the list of fields and methods of the class do not appear, then there is something wrong with the code. Go back and check it.
  1. 57.

    Add the code in Listing 13-35, to call the repair shop id method.

     
      do
      {
        /*
         Call the methods as required assigning returned
         values to method level variables
        */
        string repairShopId = myClaimDetailsInstance.ReadTheRepairShopId();
      } while (numberOfClaimsEntered < numberOfClaimsBeingMade);
Listing 13-35

Call the ReadTheRepairShopId() method from the other class

This once again clearly shows the concept of classes. Using the instance of the class, we have access to the methods and fields of the class that have the public access modifier and are not static. The dot notation, a full stop after the instance name of the class, shows us those methods and fields that are accessible, as shown in Figure 13-8.

A window pops up following the use of dot notation after my Claim Details Instance. It exhibits only the accessible methods and not the private fields.

Figure 13-8

Methods in the ClaimDetails class that are accessible

  1. 58.

    Add the code in Listing 13-36, to call the method to write the repair shop id to the array.

     
  do
  {
    /*
     Call the methods as required assigning returned
     values to method level variables
    */
    string repairShopId = myClaimDetailsInstance.ReadTheRepairShopId();
    /*
    Call the WriteRepairShopIdToTheArray method passing it
    the value to be written
    */ myClaimDetailsInstance.WriteRepairShopIdToTheArray(repairShopId);
  } while (numberOfClaimsEntered < numberOfClaimsBeingMade);
Listing 13-36

Call the WriteRepairShopIdToTheArray() method

  1. 59.

    Add the code in Listing 13-37, to call the two methods we require to read the policy number and then write it to the array.

     
   /*
   Call the WriteRepairShopIdToTheArray method passing it
   the value to be written
   */
myClaimDetailsInstance.WriteRepairShopIdToTheArray(repairShopId);
   string vehiclePolicyNumber = myClaimDetailsInstance.ReadTheVehiclePolicyNumber();
   myClaimDetailsInstance.WriteVehiclePolicyNumberToTheArray(vehiclePolicyNumber);
 } while (numberOfClaimsEntered < numberOfClaimsBeingMade);
Listing 13-37

Call the read and write policy number methods

  1. 60.

    Add the code in Listing 13-38, to call the two methods we require to read the amount being claimed and then write it to the array and then call the method that accumulates the total for all claims.

     
   string vehiclePolicyNumber = myClaimDetailsInstance.ReadTheVehiclePolicyNumber();
   myClaimDetailsInstance.WriteVehiclePolicyNumberToTheArray(vehiclePolicyNumber);
   double claimAmount = myClaimDetailsInstance.ReadTheAmountBeingClaimed();
   myClaimDetailsInstance.WriteClaimAmountToTheArray(claimAmount);
   totalOfAllClaims = myClaimDetailsInstance.AccumulateClaimAmount(claimAmount, totalOfAllClaims);
 } while (numberOfClaimsEntered < numberOfClaimsBeingMade);
Listing 13-38

Call the read and write claim amount methods

  1. 61.

    Add the code in Listing 13-39, to call the two methods we require to read the repair date and then write it to the array.

     
    totalOfAllClaims = myClaimDetailsInstance.AccumulateClaimAmount(claimAmount, totalOfAllClaims);
    DateTime claimDate = myClaimDetailsInstance.ReadTheRepairDate();
    myClaimDetailsInstance.WriteRepairDateToTheArray(claimDate);
  } while (numberOfClaimsEntered < numberOfClaimsBeingMade);
Listing 13-39

Call the read and write claim date methods

Now we have the bulk of the work done because we have our methods in one class and we have called the methods from the other class with the Main() method to get the user input and store the details in an array.

The numberOfClaimsEntered variable in the ClaimDetails class is private and cannot be accessed from the ClaimApplication class so we will need to make it available through its property accessor.
  1. 62.

    The start of the Main() method should be as shown in Listing 13-40.

     
    static void Main(string[] args)
    {
      double vatAmount = 0.00, totalOfAllClaims = 0.00
      ClaimDetails myClaimDetailsInstance = new ClaimDetails();
Listing 13-40

Remove the method-level variable

  1. 63.

    Add the code in Listing 13-41, to increment the number of claims that have been entered by one using the static field in the other class.

     
    DateTime claimDate = myClaimDetailsInstance.ReadTheRepairDate();
    myClaimDetailsInstance.WriteRepairDateToTheArray(claimDate);
    /* Increment the loop counter by 1 */
    myClaimDetailsInstance.numberOfClaimsEntered++;
  } while (numberOfClaimsEntered < numberOfClaimsBeingMade);
Listing 13-41

Increment the number of claims entered counter

We will see an error message under the numberOfClaimsEntered, and if we hover over it, we see that the protection level is making it inaccessible, as in Figure 13-9.

A pop-up window exhibits the inaccessibility issue regarding the use of the number Of Claims Entered in the line of code. It exhibits 32-bit signed integer, C S 0122, and potential fixes.

Figure 13-9

Field not accessible

We will now code a property with the getter and setter, which we looked at earlier.
  1. 64.

    Open the ClaimDetails class.

     
  2. 65.

    Right-click the numberOfClaimsEntered field.

     
  3. 66.

    Choose Quick Actions and Refactorings as shown in Figure 13-10.

     

A context menu for the number Of Claims Entered exhibits the highlighted Quick Actions and Refactorings option above Rename. Both have keyboard shortcuts.

Figure 13-10

Right-click the field and choose Quick Actions and Refactorings

  1. 67.

    Choose Encapsulate field : numberOfClaimsEntered (but still use field) as shown in Figure 13-11.

     

A 9-part menu exhibits various functions under Quick Actions and Refactorings. In the Encapsulate field, the number Of Claims Entered but still used field is highlighted.

Figure 13-11

Encapsulate the field

The accessor is created for us in our code, and we can move it from the position it has been placed in if we wish to do so or reformat it so it is not all coded on one line, as in Listing 13-42.
    static string[] repairShopClaims = new string[8];
    public int NumberOfClaimsEntered
    {
      get => numberOfClaimsEntered;
      set => numberOfClaimsEntered = value;
    }
    /******************* METHOD ONE ******************/
    public int HowManyClaimsAreBeingMade()
    {
Listing 13-42

The accessor for numberOfClaimsEntered is added to the class

  1. 68.

    Open the ClaimApplication class.

     
We will see that the error still exists because we are still trying to use the private field, numberOfClaimsEntered, directly instead of using its accessor, which is called NumberOfClaimsEntered. Notice the capital N as the first letter of the accessor. Figure 13-12 shows how the property, get and set, would appear when we use the dot notation.

A context menu exhibits the highlighted Number Of Claims Entered accessor above other entries on the right of get and set with a semicolon each within curly brackets.

Figure 13-12

NumberOfClaimsEntered property

  1. 69.

    Amend the call to use the NumberOfClaimsEntered accessor. Inside the while() remove the old method variable and replace it with the instance variable NumberOfClaimsEntered accessor, as in Listing 13-43.

     
        DateTime claimDate = myClaimDetailsInstance.ReadTheRepairDate();
        myClaimDetailsInstance.WriteRepairDateToTheArray(claimDate);
    /* Increment the loop counter by 1 */
    myClaimDetailsInstance.NumberOfClaimsEntered++;
  } while (myClaimDetailsInstance.NumberOfClaimsEntered < numberOfClaimsBeingMade);
    } // End of Main() method
  } // End of ClaimApplication class
} // End of Chapter13 namespace
Listing 13-43

The accessor NumberOfClaimsEntered is used (capital N)

Now we will
  • Call the DetermineVATAmount() method, passing it the totalOfAllClaims and the vatAmount.

  • Call the DisplayAllItemsInTheArray() method.

  • Write the total of all claims to the console.

  • Call one of the DisplayInvoiceReceipt() methods, passing it the totalOfAllClaims and the vatAmount.

  • Call one of the DisplayInvoiceReceipt() methods, passing it the totalOfAllClaims, the vatAmount, and a message.

The two DisplayInvoiceReceipt methods have the same name but have different parameters, and this is referred to as method overloading.
  1. 70.

    Add the ClaimApplication code in Listing 13-44, to call the method that will display the invoice receipt based on the total of the claims, the VAT amount, and the message string.

     
   } while (myClaimDetailsInstance.NumberOfClaimsEntered < numberOfClaimsBeingMade);
   vatAmount = myClaimDetailsInstance.DetermineVATAmount(totalOfAllClaims, vatAmount);
   myClaimDetailsInstance.DisplayAllItemsInTheArray();
   Console.WriteLine("The total amount claimed is: " + totalOfAllClaims);
   myClaimDetailsInstance.DisplayInvoiceReceipt(totalOfAllClaims, vatAmount);
   myClaimDetailsInstance.DisplayInvoiceReceipt(totalOfAllClaims, vatAmount, " " + "Thank you for your claims they will be processed today");
    } // End of Main() method
  } // End of ClaimApplication class
} // End of Chapter13 namespace
Listing 13-44

Call the method that will display the invoice

Great. All the methods have been placed in one class, and then they are called from another class that has the Main() method. We could have made other classes and moved some of the methods to these classes, but we are just trying to appreciate that we can have separate classes with one class having its methods called from the main class. This is plenty to understand for now. We now need to test the structure.
  1. 71.

    Click the File menu.

     
  2. 72.

    Choose Save All.

     
  3. 73.

    Click the Debug menu.

     
  4. 74.

    Choose Start Without Debugging.

     
The console window will appear and ask the user to input the number of claims to be made.
  1. 75.

    Type 2 and press the Enter key.

     
The console window will appear and ask the user to input the repair shop id.
  1. 76.

    Type RS000001 for the repair shop id and press the Enter key.

     
The console will now ask the user to input the vehicle policy number.
  1. 77.

    Type VP000001 and press the Enter key.

     
The console will now ask the user to input the claim amount.
  1. 78.

    Type 1200 and press the Enter key.

     
The console will now ask the user to input the date of the repair.
  1. 79.

    Type 2021/10/01 and press the Enter key.

     
The questions are asked again for the second claim.
  1. 80.

    Type RS000001 for the repair shop id and press the Enter key.

     
The console will now ask the user to input the vehicle policy number.
  1. 81.

    Type VP000002 and press the Enter key.

     
The console will now ask the user to input the claim amount.
  1. 82.

    Type 3600 and press the Enter key.

     
The console will now ask the user to input the date of the repair.
  1. 83.

    Type 2021/10/01 and press the Enter key.

     
The invoice receipt will be displayed as shown in Figure 13-13.

A console window exhibits the invoice for vehicle repairs with values for Nett claim, V A T amount, and Total amount between lines of asterisks.

Figure 13-13

Receipt, having used classes

  1. 84.

    Press the Enter key to close the console window.

     

This is the same application as MethodsValue() and the same invoice receipt, with different amounts. The big difference is the separation of the methods from the class that contains the Main() method.

This is just an example to show how classes work. It certainly is not a “polished” application, and it can be improved upon, but the important things to take away from what we have done so far are as follows:
  • A class can contain fields.

  • A class can contain methods.

  • To use a class from within another class, we create an instance of the class – this is called instantiation.

  • The instantiated class gives us access to the fields and methods of the class.

Constructor

In the ClaimApplication class, we made an instance of the ClaimDetails class so we could access the fields and methods of the class as shown in Listing 13-45.
  ClaimDetails myClaimDetailsInstance = new ClaimDetails();
Listing 13-45

Creating an instance of the class

The new ClaimDetails() section of the code means we are not passing in any arguments to the class; this is why there are no values between the brackets (). This means we are calling the default constructor, and we read earlier that the constructor “method” can be used to initialize the value of the fields in the class. It may be used to initialize all the fields or some of them, or in the case of a default constructor, none of the fields are initialized – they just have their default values.

Refreshing what we read earlier, a constructor has the following features :
  • It must have the same name as the class. We will therefore use the name ClaimDetails.

  • It must have an access modifier of public.

  • It does not have a return type, not even void.

  • It takes in arguments of the same type as the fields being initialized.

Next

  • We will create a constructor that has a DateTime parameter.

  • The new constructor will therefore overwrite the default constructor.

  • We will use a DateTime field with a readonly keyword, which means the field can only be assigned a value as part of the declaration or in a constructor in the same class. The readonly field can be assigned and reassigned multiple times within the field declaration and constructor.

  • By setting the date field to the date read from the computer, we will not need to have the method that asks the user to input the date of the claim, method 9, so this method will not be called from the Main method.

  • When we then write the date to the array, we will use the new DateTime field we are setting up in the class and initializing with the computer date.

  • For now, we will leave the method in the ClaimDetails class .

  1. 1.

    In the ClaimDetails amend the code to add the readonly DateTime field and a constructor that will set the date field to the current computer date, as in Listing 13-46.

     
  internal class ClaimDetails
  {
    int numberOfClaimsEntered;
    readonly DateTime claimDate;
    static int arrayPositionCounter = 0;
    /*
   The array is going to hold the data for 2 claims.
   Each claim has four pieces of information. The number of
   data items is therefore 2 multiplied by 4 = 8.
   So, we will make the array for this example of size 8.
   Not the best way to do things but fine for now.
   */
    static string[] repairShopClaims = new string[8];
    /*
    The constructor has the same name as the class, it has an
    access modifier of public, it takes an argument of data
    type DateTime as this is the same data type as the field,
    claimDate, that is being initialised, and it does not
    return a value so there is no return type
    */
    public ClaimDetails(DateTime claimDate)
    {
      this.claimDate = Convert.ToDateTime(claimDate);
    } // End of constructor that takes in a date
Listing 13-46

Add a new constructor that has a DateTime parameter

Now that we have created the constructor, we can use it when creating the instance of the class from within the Main() method. If we look in the ClaimApplication class, we will now see that there is an error in the line that instantiates the ClaimDetails class. This is because there is no default constructor, and the new constructor expects a DateTime value to be passed to it. This can be seen in the message box that appears when we hover over the red underscore. We will do the fix “manually” so do not click Create constructor fix.

An error message exhibits a lack of argument, simplification of new expression, and option to reveal potential fixes for new Claim Details parentheses.

Figure 13-14

Error because we now have no default constructor

  1. 2.

    Amend the ClaimApplication code , as in Listing 13-47, to read the date from the computer.

     
    static void Main(string[] args)
    {
      double vatAmount = 0.00, totalOfAllClaims = 0.00;
      // Read the date from the computer clock
      DateTime localDate = DateTime.Now;
      ClaimDetails myClaimDetailsInstance = new ClaimDetails();
Listing 13-47

Read the date from the computer

  1. 3.

    Amend the code, as in Listing 13-48, to pass the DateTime to the constructor.

     
    // Read the date from the computer clock
    DateTime localDate = DateTime.Now;
    ClaimDetails myClaimDetailsInstance = new ClaimDetails(localDate);
Listing 13-48

Use the custom constructor, passing in the DateTime

  1. 4.

    As we now have the date, we do not need to ask the user to input the date. The method call can be removed or commented out, as it is not used, as in Listing 13-49.

     
    totalOfAllClaims = myClaimDetailsInstance.AccumulateClaimAmount(claimAmount, totalOfAllClaims);
    //DateTime claimDate = myClaimDetailsInstance.ReadTheRepairDate();
    myClaimDetailsInstance.WriteRepairDateToTheArray(claimDate);
    /* Increment the loop counter by 1 */
    myClaimDetailsInstance.NumberOfClaimsEntered++;
  } while (myClaimDetailsInstance.NumberOfClaimsEntered < numberOfClaimsBeingMade);
Listing 13-49

Comment the line where the repair date reading method is called

Now we need to call the claimDate field from the ClaimDetails class but it is private, so we need to create the property with the get and set. This is the same process as we followed for the numberOfClaimsEntered field.
  1. 5.

    Right-click the claimDate field in the ClaimDetails class.

     
  2. 6.

    Choose Quick Actions and Refactorings.

     
  3. 7.

    Choose Encapsulate field: claimDate (but still use field).

     
The accessor is created for us in our code, and we can move it from the position it has been placed in if we wish to do so. As the field is readonly, the accessor only allows us to get the date, not set the date.
  1. 8.

    Now we need to call the DateTime field so we can write the date to the array. In the ClaimApplication, class amend the code to call the accessor, as in Listing 13-50.

     
    totalOfAllClaims = myClaimDetailsInstance.AccumulateClaimAmount(claimAmount, totalOfAllClaims);
    //DateTime claimDate = myClaimDetailsInstance.ReadTheRepairDate();
    myClaimDetailsInstance.WriteRepairDateToTheArray(myClaimDetailsInstance.ClaimDate);
    /* Increment the loop counter by 1 */
Listing 13-50

Call the DateTime field through its property

In order to see the date being displayed, we need to iterate the array and display the items within it. Now we can test the code to ensure the constructor works. If it does, the array will be populated with the current date.
  1. 9.

    Click the File menu.

     
  2. 10.

    Choose Save All.

     
  3. 11.

    Click the Debug menu.

     
  4. 12.

    Choose Start Without Debugging.

     
The console window will appear and ask the user to input the number of claims to be made.
  1. 13.

    Type 2 and press the Enter key.

     
The console window will appear and ask the user to input the repair shop id.
  1. 14.

    Type RS000001 for the repair shop id and press the Enter key.

     
The console will now ask the user to input the vehicle policy number.
  1. 15.

    Type VP000001 and press the Enter key.

     
The console will now ask the user to input the claim amount.
  1. 16.

    Type 1200 and press the Enter key.

     

We have removed the call to the method that asks the user to input the date of the repair so we will not be asked for the date of the repair.

The questions are asked again for the second claim.
  1. 17.

    Type RS000001 for the repair shop id and press the Enter key.

     
The console will now ask the user to input the vehicle policy number.
  1. 18.

    Type VP000002 and press the Enter key.

     
The console will now ask the user to input the claim amount.
  1. 19.

    Type 3600 and press the Enter key.

     
The invoice receipt will be displayed as shown in Figure 13-15.

A console window depicts similar computer date entries among items in the array in the invoice receipt. Invoice for vehicle repairs is also exhibited.

Figure 13-15

The computer date is displayed

  1. 20.

    Press the Enter key to close the console window.

     

Another Constructor

We will now create a second constructor, which will set the date field and a message field of data type String. This new constructor will therefore be different from the first constructor, as it has two arguments as opposed to one, This is constructor overloading.

We will need to create an additional field called message of data type string and we will explicitly set it as private.
  1. 21.

    Amend the ClaimDetails code , as in Listing 13-51, to add the field called message.

     
internal class ClaimDetails
  {
    int numberOfClaimsEntered = 0;
    readonly DateTime claimDate;
    private readonly string message = "";
    static int arrayPositionCounter = 0;
Listing 13-51

Add a String field and assign it a value

We will now add the second constructor, which will set the date field to the current computer date and the message field to whatever message is passed in when the ClaimDetails class is instantiated. We will use this constructor to call the first constructor to set the date, which illustrates the concept of constructor chaining, which helps us avoid code duplication. We therefore add :this(claimDate) to the constructor.
  1. 22.

    Amend the ClaimDetails code, as in Listing 13-52, to add the second constructor.

     
   public ClaimDetails(DateTime claimDate)
    {
      this.claimDate = Convert.ToDateTime(claimDate);
    } // End of constructor that takes in a date
    /*
    This is a second constructor that accepts two
    arguments and the values that are passed to the constructor
    are used to set the value of the field called claimDate
    and the field called message. The constructor calls the
    first constructor to assign the value to the DateTime field
    As the constructor has two arguments it is different
    from the first constructor
    */
    public ClaimDetails(DateTime claimDate, string message):this(claimDate)
    {
      this.message = message;
    } // End of constructor that takes in a date and a message
Listing 13-52

Add the second constructor

Now we will look back at the call to the DisplayInvoiceReceipt() method in the ClaimApplication class that we added, shown in Listing 13-53.
myClaimDetailsInstance.DisplayInvoiceReceipt(totalOfAllClaims, vatAmount, " " + "Thank you for your claims they will be processed today");
Listing 13-53

Calling the method to display the invoice receipt

  • Here we are calling the method DisplayInvoiceReceipt() and we have passed it a message, which the method uses to display the message.

  • However, we have just created a constructor that accepts a message string and assigns this string value to the field called message.

  • As we have the new constructor, we could pass our message at the time we instantiate the class, and the message will then exist in the class.

  • We can then remove method 15 where we accepted the message.

  • We can call method 14, which accepts only two parameters, not the message:

DisplayInvoiceReceipt(double totalValueOfClaimsPassedIn, double vatPassedIn)
  • We can then add an extra line to method 14 to display the message field because we have direct access to the field in the other class.

As the message is initialized as “”, if there is no message created by our constructor, a blank line space will be written for the message. What this means is if we leave the original instantiation, which uses the first constructor, no message is passed in, so the message will use the value assigned to it, “”.
  1. 23.

    Amend the ClaimDetails class code, as in Listing 13-54, to remove method 15 or simply comment the method code.

     
    ///******************* METHOD FIFTEEN ******************/
    //public void DisplayInvoiceReceipt(double
    //totalValueOfClaimsPassedIn, double vatPassedIn, string
    //messagePassedIn)
    //{
    //  Console.WriteLine("********************************");
    //  Console.WriteLine(" Invoice for vehicle repairs ");
    //  Console.WriteLine("Nett claim " + (totalValueOfClaimsPassedIn - vatPassedIn) + " ");
    //  Console.WriteLine("VAT amount " + vatPassedIn + " ");
    //  Console.WriteLine("Total amount " + totalValueOfClaimsPassedIn + " ");
    //  Console.WriteLine(messagePassedIn);
    //  Console.WriteLine("********************************");
    //} // End of method DisplayInvoiceReceipt
  }  // End of ClaimDetails class
}  // End of Chapter13 namespace
Listing 13-54

Comment all of method 15 (don’t worry about YAGNI!)

We will now see that the ClaimApplication class has an error as it is trying to use the DisplayInvoiceReceipt() method that has three arguments, as shown in Figure 13-16.

An error message depicts nonexistent overload for the Display Invoice Receipt method with 3 arguments from a line that starts with my Claim Details Instance.

Figure 13-16

Error as the method accepting three arguments does not exist

Amend the code by removing the line that has the error. We are already calling the DisplayInvoiceReceipt() method in the line above this one.
  1. 24.

    Amend the code to delete the line of code with the error. With this line removed, the code should be as shown in Listing 13-55.

     
      vatAmount = myClaimDetailsInstance.DetermineVATAmount(totalOfAllClaims, vatAmount);
      myClaimDetailsInstance.DisplayAllItemsInTheArray();
      Console.WriteLine("The total amount claimed is: " + totalOfAllClaims);
      myClaimDetailsInstance.DisplayInvoiceReceipt(totalOfAllClaims, vatAmount);
    } // End of Main() method
Listing 13-55

Remove the second call to the DisplayInvoiceReceipt() method

Now we need to change the instantiation code line, since it is currently using the constructor that accepts one parameter of type DateTime. In Listing 13-56 the new code line is shown above the old code line, which has been commented, and this is simply to help us understand what to do. If we are to stick with the YAGNI principle, we can just remove the commented line.
  1. 25.

    Now amend the instantiation code line, in the ClaimApplication class , to pass the two values to the new constructor, as in Listing 13-56.

     
    static void Main(string[] args)
    {
      double vatAmount = 0.00, totalOfAllClaims = 0.00;
      // Read the date from the computer clock
      DateTime localDate = DateTime.Now;
      ClaimDetails myClaimDetailsInstance = new ClaimDetails(localDate, " Thank you for your claims they will be processed today");
      // ClaimDetails myClaimDetailsInstance = new ClaimDetails(localDate);
      int numberOfClaimsBeingMade = myClaimDetailsInstance.HowManyClaimsAreBeingMade();
Listing 13-56

Add the two arguments to the method call

  1. 26.

    Amend the DisplayInvoiceReceipt() method in the ClaimDetails class to add the new line, which will print the message line, as in Listing 13-57.

     
    /******************* METHOD FOURTEEN ******************/
    public void DisplayInvoiceReceipt(double totalValueOfClaimsPassedIn, double vatPassedIn)
    {
      Console.WriteLine(" Invoice for vehicle repairs ");
      Console.WriteLine("Nett claim " + (totalValueOfClaimsPassedIn - vatPassedIn) + " ");
      Console.WriteLine("VAT amount " + vatPassedIn + " ");
      Console.WriteLine("Total amount " + totalValueOfClaimsPassedIn + " ");
      Console.WriteLine(message);
    } // End of method DisplayInvoiceReceipt()
Listing 13-57

Display the message

  1. 27.

    Open the ClaimApplication class.

     
  2. 28.

    Click the File menu.

     
  3. 29.

    Choose Save All.

     
  4. 30.

    Click the Debug menu.

     
  5. 31.

    Choose Start Without Debugging.

     
The console window will appear and ask the user to input the number of claims to be made.
  1. 32.

    Type 2 and press the Enter key.

     
The console window will appear and ask the user to input the repair shop id.
  1. 33.

    Type RS000001 for the repair shop id and press the Enter key.

     
The console will now ask the user to input the vehicle policy number.
  1. 34.

    Type VP000001 and press the Enter key.

     
The console will now ask the user to input the claim amount.
  1. 35.

    Type 1200 and press the Enter key.

     

We have removed the call to the method that asks the user to input the date of the repair so we will not be asked for the date of the repair.

The questions are asked again for the second claim.
  1. 36.

    Type RS000001 for the repair shop id and press the Enter key.

     
The console will now ask the user to input the vehicle policy number.
  1. 37.

    Type VP000002 and press the Enter key.

     
The console will now ask the user to input the claim amount.
  1. 38.

    Type 3600 and press the Enter key.

     
The invoice receipt will be displayed as shown in Figure 13-17.

A console window depicts similar computer date entries in the invoice receipt and a thank you message in the invoice for vehicle repairs below.

Figure 13-17

The message and the computer date are displayed

  1. 39.

    Press the Enter key to close the console window.

     
Now we will amend the instantiation code line to pass only one value, the date, to the constructor. This means the first constructor will be used, and hence the message field will not be changed – it will have the value we entered, “”.
  1. 40.

    Amend the instantiation code line to comment out the first call and add the new call to the constructor, as in Listing 13-58.

     
static void Main(string[] args)
 {
   double vatAmount = 0.00, totalOfAllClaims = 0.00;
   // Read the date from the computer clock
   DateTime localDate = DateTime.Now;
   //ClaimDetails myClaimDetailsInstance = new ClaimDetails(localDate, " Thank you for" +
   //  " your claims they will be processed today");
   ClaimDetails myClaimDetailsInstance = new ClaimDetails(localDate);
   int numberOfClaimsBeingMade
     = myClaimDetailsInstance.HowManyClaimsAreBeingMade();
Listing 13-58

Use the constructor with one parameter

  1. 41.

    Click the File menu.

     
  2. 42.

    Choose Save All.

     
  3. 43.

    Click the Debug menu.

     
  4. 44.

    Choose Start Without Debugging.

     
The console window will appear and ask the user to input the number of claims to be made.
  1. 45.

    Type 2 and press the Enter key.

     
The console window will appear and ask the user to input the repair shop id.
  1. 46.

    Type RS000001 for the repair shop id and press the Enter key.

     
The console will now ask the user to input the vehicle policy number.
  1. 47.

    Type VP000001 and press the Enter key.

     
The console will now ask the user to input the claim amount.
  1. 48.

    Type 1200 and press the Enter key.

     

We have removed the call to the method that asks the user to input the date of the repair so we will not be asked for the date of the repair.

The questions are asked again for the second claim.
  1. 49.

    Type RS000001 for the repair shop id and press the Enter key.

     
The console will now ask the user to input the vehicle policy number.
  1. 50.

    Type VP000002 and press the Enter key.

     
The console will now ask the user to input the claim amount.
  1. 51.

    Type 3600 and press the Enter key.

     
The invoice receipt will be displayed as shown in Figure 13-18.

A console window exhibits the absence of a message below the invoice receipt and invoice for vehicle repairs.

Figure 13-18

No message displayed using the constructor with one parameter

  1. 52.

    Press the Enter key to close the console window.

     

Additional Example for Classes and Objects

Now we will consolidate what we have learned in the previous section regarding classes . Here we will take another example and create a class with methods and fields and call them from another class with a Main() method. The example we will use will involve some mathematical formulae and be related to shapes.
  1. 1.

    Right-click the Chapter13 project.

     
  2. 2.

    Choose Add.

     
  3. 3.

    Choose Class.

     
  4. 4.

    Name the class ShapeCalculator.cs.

     
  5. 5.

    Click the Add button.

     
  6. 6.

    Amend the code, as in Listing 13-59, by adding a Main() method.

     
namespace Chapter13
{
  internal class ShapeCalculator
  {
    static void Main(string[] args)
    {
    } // End of Main() method
  } // End of ShapeCalculator class
} // End of Chapter13 namespace
Listing 13-59

Class with a Main() method as the entry point for the program

  1. 7.

    Right-click the Chapter13 project in the Solution Explorer panel.

     
  2. 8.

    Choose Properties.

     
  3. 9.

    In the Startup object drop-down list, choose the ShapeCalculator file.

     
  4. 10.

    Close the Properties window.

     

CircleFormulae Class

  1. 1.

    Right-click the Chapter13 project.

     
  2. 2.

    Choose Add.

     
  3. 3.

    Choose Class.

     
  4. 4.

    Name the class CircleFormulae .cs.

     
  5. 5.

    Click the Add button.

     
  6. 6.

    Amend the code, as in Listing 13-60, by adding the start of a method that will calculate the area of a circle.

     
namespace Chapter13
{
  internal class CircleFormulae
  {
   /*
   This is a method that will ask the user to input the length
   of the radius of the circle, calculate the area of the circle
   and display the area of the circle in the console window
   */
   public void AreaOfCircle()
   {
   } //End of AreaOfCircle method
  } // End of CircleFormulae class
} // End of Chapter13 namespace
Listing 13-60

Class with NO Main() method

  1. 7.

    Amend the code, as in Listing 13-61, to create variables that will hold the radius and the area of the circle, setting their initial value to be 0.

     
    public void AreaOfCircle()
   {
      /*
      Create two variables of data type double to hold the
      value of the radius input by the user and the calculated
      area of the circle, initialise the two variables to zero
      */
      double radiusLength = 0;
      double areaOfCircle = 0;
    } //End of AreaOfCircle method
Listing 13-61

Create and initialize the variables

  1. 8.

    Amend the code, as in Listing 13-62, to ask the user to input the radius of the circle and assign the value to the radiusLength variable.

     
      double areaOfCircle = 0;
      // Read the user input for the size of the radius
      Console.WriteLine("What size is the radius? ");
      radiusLength = Convert.ToDouble(Console.ReadLine());
    } //End of AreaOfCircle method
Listing 13-62

Read the radius input and convert it to type double

Remember we talked about PI before as being a constant in the Math class.
  1. 9.

    Now add the code in Listing 13-63, to calculate the area of the circle.

     
      radiusLength = Convert.ToDouble(Console.ReadLine());
      // Calculate the area of the circle with the formula
      areaOfCircle = Math.PI * radiusLength * radiusLength;
    } //End of AreaOfCircle method
Listing 13-63

Add the formula for the area of a circle

We will now use the Format() method of the String class to display the output using two decimal places. There are other ways to display formatted data, and we will look at these in detail in Chapter 15. For now it is fine to use String.Format() to display our output.
  1. 10.

    Now add the code in Listing 13-64, to display the area and radius, using the Format() method.

     
      // Calculate the area of the circle with the formula
      areaOfCircle = Math.PI * radiusLength * radiusLength;
      Console.WriteLine(String.Format(" A circle with radius {0:0.#} has an area of {1:0.##}",
        radiusLength, areaOfCircle));
    } //End of AreaOfCircle method
Listing 13-64

Display the radius and area of the circle

Now that we have created a class with a method in it, we will be able to call the method from the Main() method in the ShapeCalculator class. But remember, we will need to instantiate the class rather than using the class template.
  1. 11.

    Open the ShapeCalculator class and create an instance of the CircleFormulae class, calling it myCircleFormulae, as in Listing 13-65.

     
    static void Main(string[] args)
    {
      // Instantiate the CircleFormulae class
      CircleFormulae myCircleFormulae = new CircleFormulae();
    } // End of Main() method
Listing 13-65

Instantiate the CircleFormulae class using a default constructor

Now we need to call the AreaOfCircle() method from the other class. As we type myCircleFormulae and add the ., as shown in Figure 13-19, we should automatically see any accessible fields and methods that belong in the CircleFormulae class, or more correctly to the myCircleFormulae instance of the class. Remember a class is made up of fields and methods.

A window pops up following the use of dot notation after the my Circle Formulae instance. Area Of Circle is highlighted among other methods of the class.

Figure 13-19

Methods accessible in the CircleFormulae class – no fields exist

  1. 12.

    Now add the code in Listing 13-66, to call the AreaOfCircle() method .

     
    static void Main(string[] args)
    {
      // Instantiate the CircleFormulae class
      CircleFormulae myCircleFormulae = new CircleFormulae();
      myCircleFormulae.AreaOfCircle();
    } // End of Main() method
Listing 13-66

Call the AreaOfCircle() method that is in the other class

  1. 13.

    Click the File menu.

     
  2. 14.

    Choose Save All.

     
  3. 15.

    Click the Debug menu.

     
  4. 16.

    Choose Start Without Debugging.

     
The console window will appear and ask the user to input the radius of the circle.
  1. 17.

    Type 10 and press the Enter key.

     
The console window will show the area of the circle, as shown in Figure 13-20.

A console window exhibits 314.16 as the area of a circle with a radius size of 10 after the Area Of Circle parentheses method is called.

Figure 13-20

AreaOfCircle() method called and working

  1. 18.

    Press the Enter key to close the console window.

     
This is excellent! Our method has been called from another class. We will now add another method, just after the AreaOfCircle method and inside the class, to calculate the circumference of the circle.
  1. 19.

    Amend the code, as in Listing 13-67, in the CircleFormulae class to add the start of a method that will calculate the circumference of the circle.

     
    } //End of AreaOfCircle method
    /*
    This is a method that will accept the value of the radius
    passed to it. The radius has been obtained in the
    AreaOfCircle method and then the AreaOfCircle() method
    will call this new CircumferenceOfCircle() method passing
    it the value of the radius. This method will then calculate
    the circumference and display the value in the console window
    */
    public void CircumferenceOfCircle(double radiusPassedIn)
    {
    } // End of CircumferenceOfCircle method
  } // End of CircleFormulae class
} // End of Chapter13 namespace
Listing 13-67

Add a method to calculate the circumference of the circle

  1. 20.

    Amend the code, as in Listing 13-68, to create a variable to hold the circumference of the circle.

     
    public void CircumferenceOfCircle(double radiusPassedIn)
    {
      /*
      Create a variable of data type double to hold the value
      calculated for the circumference of the circle.
      Initialise the variable to zero.
      We have the radius as it is passed into this method.
      */
      double circumferenceOfCircle = 0;
    } // End of CircumferenceOfCircle method
Listing 13-68

Create and initialize the variable for the circumference

  1. 21.

    Now add the code in Listing 13-69, to calculate the circumference.

     
    public void CircumferenceOfCircle(double radiusPassedIn)
    {
      /*
      Create a variable of data type double to hold the value
      calculated for the circumference of the circle.
      Initialise the variable to zero.
      We have the radius as it is passed into this method.
      */
      double circumferenceOfCircle = 0;
      //Calculate the circumference with the formula
      circumferenceOfCircle = 2 * Math.PI * radiusPassedIn;
    } // End of CircumferenceOfCircle method
Listing 13-69

Add the formula for the circumference of a circle

  1. 22.

    Now add the code in Listing 13-70, to display the circumference and radius, using the Format() method.

     
      double circumferenceOfCircle = 0;
      //Calculate the circumference with the formula
      circumferenceOfCircle = 2 * Math.PI * radiusPassedIn;
      Console.WriteLine(String.Format(" A circle with radius {0:0.#} has a circumference of {1:0.##}", radiusPassedIn, circumferenceOfCircle));
    } // End of CircumferenceOfCircle method
Listing 13-70

Display the radius and circumference of the circle

Now that we have created the second method, we will call it from the first method, AreaOfCircle(), passing it the radius that has been input by the user.
  1. 23.

    In the AreaOfCircle() method, call the CircumferenceOfCircle() method, as in Listing 13-71.

     
      Console.WriteLine(String.Format(" A circle with radius {0:0.#} has an area of  {1:0.##}", radiusLength, areaOfCircle));
      /*
      Now call the method which calculates the circumference
      of the circle using the radius the user has input.
      We call the method and pass the radius as a parameter.
      */
      CircumferenceOfCircle(radiusLength);
    } //End of areaOfCircle method
Listing 13-71

Call the CircumferenceOfCircle() method

  1. 24.

    Click the File menu.

     
  2. 25.

    Choose Save All.

     
  3. 26.

    Open the ShapeCalculator class.

     
  4. 27.

    Click the Debug menu.

     
  5. 28.

    Choose Start Without Debugging.

     
The console window will appear and ask the user to input the radius of the circle, as shown in Figure 13-21.
  1. 29.

    Type 10 and press the Enter key.

     

A console window depicts 62.83 as a circumference of a circle with a 10 radius and 314.16 area post- Circumference Of Circle parentheses method call.

Figure 13-21

CircumferenceOfCircle() method called and working

  1. 30.

    Press the Enter key to close the console window.

     

We see two decimal places in the circumference as we used 0.## in the Format() method. This is excellent! Our two methods that contain the business logic, the formulae, were created in a class and have been called from another class.

We can see that we have used the principle of “separation of concern,” where we have kept our circle formulae separate from the class with the Main() method. We will now reinforce the principle of “separation of concern” by creating another class that will be related to a rectangle and will hold any formula related to a rectangle.

RectangleFormulae Class

  1. 1.

    Right-click the Chapter13 project.

     
  2. 2.

    Choose Add.

     
  3. 3.

    Choose Class.

     
  4. 4.

    Name the class RectangleFormulae .cs.

     
  5. 5.

    Click the Add button.

     
We will create a method for the area of a rectangle. The formula for the area of a rectangle is the length multiplied by the breadth. This formula will therefore be our business logic. To calculate the area of the rectangle, we will ask the user to input the length and breadth of the rectangle they require.
  1. 6.

    Amend the code, as in Listing 13-72, by adding the start of a method that will calculate the area of a rectangle.

     
namespace Chapter13
{
  internal class RectangleFormulae
  {
    /*
    This is a method that will ask the user to input the
    length of the rectangle, then ask them for the breadth of
    the rectangle, calculate the area of the rectangle and
    display the area of the rectangle in the console window
    */
    public void AreaOfRectangle()
    {
    } // End of AreaOfRectangle method
  } // End of RectangleFormulae class
} // End of Chapter13 namespace
Listing 13-72

Creating the method for the area of a rectangle

  1. 7.

    Amend the code, as in Listing 13-73, to create variables to hold the length, breadth, and area of the rectangle and initialize them to 0.

     
    public void areaOfRectangle()
    {
      /*
      Create three variables of data type double to hold the
      value of the length and breadth as input by the user and
      the calculated area of the rectangle.
      Initialise the three variables to zero.
      */
      double lengthOfRectangle = 0;
      double breadthOfRectangle = 0;
      double areaOfRectangle = 0;
    } // End of AreaOfRectangle method
Listing 13-73

Create and initialize the variables for the rectangle formulae

  1. 8.

    Amend the code, as in Listing 13-74, to ask the user to input the length and breadth of the rectangle and then convert the inputs to type double.

     
      double breadthOfRectangle = 0;
      double areaOfRectangle = 0;
      Console.WriteLine(" What is the rectangle length? ");
      lengthOfRectangle = Convert.ToDouble(Console.ReadLine());
      Console.WriteLine(" What is the rectangle breadth? ");
      breadthOfRectangle = Convert.ToDouble(Console.ReadLine());
    } // End of AreaOfRectangle method
Listing 13-74

Ask for user input for length and breadth

  1. 9.

    Now add the code in Listing 13-75, to calculate the area of the rectangle.

     
      Console.WriteLine(" What is the rectangle breadth? ");
      breadthOfRectangle = Convert.ToDouble(Console.ReadLine());
      // Calculate the area of the rectangle with the formula
      areaOfRectangle = lengthOfRectangle * breadthOfRectangle;
    } // End of AreaOfRectangle method
Listing 13-75

Add the formula for the area of a rectangle

  1. 10.

    Now add the code in Listing 13-76, to display the length, breadth, and area, using the Format() method.

     
      // Calculate the area of the rectangle with the formula
      areaOfRectangle = lengthOfRectangle * breadthOfRectangle;
      // Display the rectangle details
      Console.WriteLine(String.Format(" A rectangle with length of {0:0.#} and breadth of {1:0.#} has an area of {2:0.#}", lengthOfRectangle, breadthOfRectangle, areaOfRectangle));
      } // End of AreaOfRectangle method
Listing 13-76

Display the length, breadth, and area of the rectangle

Now that we have created another class with a method in it, we will be able to call the method from the Main() method in the ShapeCalculator class. Remember, we do not use the RectangleFormulae class directly; we make an instance of it.
  1. 11.

    Open the ShapeCalculator class and create an instance of the RectangleFormulae class, as in Listing 13-77.

     
    static void Main(string[] args)
    {
      // Instantiate the CircleFormulae class
      CircleFormulae myCircleFormulae = new CircleFormulae();
      myCircleFormulae.areaOfCircle();
      RectangleFormulae myRectangleFormulae = new RectangleFormulae();
    } // End of Main() method
Listing 13-77

Instantiate the RectangleFormulae class

Now we need to call the AreaOfRectangle() method from the other class. As we type myRectangleFormulae and add the ., as shown in Figure 13-22, we should automatically see any accessible fields and methods that belong in the RectangleFormulae class, or more correctly to the myRectangleFormulae instance of the class. Remember a class is made up of fields and methods.

A window pops up following the use of dot notation after the my Rectangle Formulae instance. Area Of Rectangle is highlighted among other class methods.

Figure 13-22

Methods accessible in the RectangleFormulae class

  1. 12.

    Now add the code in Listing 13-78, to call the AreaOfRectangle() method of our new instance class.

     
      myCircleFormulae.AreaOfCircle();
      RectangleFormulae myRectangleFormulae
      = new RectangleFormulae();
      myRectangleFormulae.AreaOfRectangle();
    } // End of Main() method
Listing 13-78

Call the AreaOfRectangle method

  1. 13.

    Click the File menu.

     
  2. 14.

    Choose Save All.

     
  3. 15.

    Click the Debug menu.

     
  4. 16.

    Choose Start Without Debugging.

     
The console window will appear and ask the user to input the radius of the circle.
  1. 17.

    Type 10 and press the Enter key.

     
The console window will ask the user to input the length of the rectangle.
  1. 18.

    Type 10.5 and press the Enter key.

     
The console window will ask the user to input the breadth of the rectangle.
  1. 19.

    Type 20.5 and press the Enter key.

     
Figure 13-23 shows the console window with the areas of the circle and rectangle.

A console window depicts an area of 215.3 below other rectangle and circle measurements post-Area Of Rectangle parentheses method call.

Figure 13-23

AreaOfRectangle() method called and working

  1. 20.

    Press the Enter key to close the console window.

     
We see one digit after the decimal point in the area of the rectangle as we used 0.# in the Format() method. This is excellent! Our method for the rectangle area has been called from another class. Now we will extend our RectangleFormulae class by adding another method, just after the method AreaOfRectangle() and inside the class, to calculate the perimeter of the rectangle.
  1. 21.

    Amend the code, as in Listing 13-79, in the RectangleFormulae class to add the method that will calculate the perimeter of the rectangle/

     
      } // End of AreaOfRectangle method
    /*
    This is a method that will accept the values of the length
    and breadth passed to it. Both values have been obtained in
    the AreaOfRectangle method and then the AreaOfRectangle()
    method will call this new PerimeterOfRectangle() method
    passing it the values of the length and breadth.
    This method will then calculate the perimeter and display
    the value in the console window
    */
    public void PerimeterOfRectangle(double lengthPassedIn,  double breadthPassedIn)
    {
    } // End of perimeterOfRectangle method
  } // End of RectangleFormulae class
} // End of Chapter13 namespace
Listing 13-79

Add the PerimeterOfRectangle() method

  1. 22.

    Amend the code, as in Listing 13-80, to create a variable to hold the perimeter of the rectangle.

     
public void PerimeterOfRectangle(double lengthPassedIn, double breadthPassedIn)
    {
      /*
      Create a variable of data type double to hold the value
      calculated for the perimeter of the rectangle. Initialise
      the variable to zero. We have the length and breadth as
      they are passed into this method
      */
      double perimeterOfRectangle = 0;
    } // End of PerimeterOfRectangle method
Listing 13-80

Add a variable that will hold the perimeter

  1. 23.

    Now add the code in Listing 13-81, to calculate the rectangle perimeter.

     
  double perimeterOfRectangle = 0;
  //Calculate the perimeter of the rectangle with the formula
  perimeterOfRectangle = 2 * (lengthPassedIn + breadthPassedIn);
} // End of PerimeterOfRectangle method
Listing 13-81

Add the formula for the perimeter of the rectangle

  1. 24.

    Now add the code in Listing 13-82, to display the perimeter of the rectangle.

     
 //Calculate the perimeter of the rectangle with the formula
 perimeterOfRectangle = 2 * (lengthPassedIn + breadthPassedIn);
 Console.WriteLine(String.Format(" A rectangle with length of {0:0.##} and breadth of {1:0.##} has a perimeter of {2:0.##}", lengthPassedIn, breadthPassedIn, perimeterOfRectangle));
    } // End of PerimeterOfRectangle method
Listing 13-82

Display the length, breadth, and perimeter of the rectangle

Now that we have created the second method for the rectangle, we will call it from the first method, AreaOfRectangle(), passing it the length and breadth.
  1. 25.

    In the AreaOfRectangle() method, add the code in Listing 13-83, to call the PerimeterOfRectangle() method.

     
  // Display the answer
  Console.WriteLine(String.Format(" A rectangle with length of {0:0.#} and breadth of {1:0.#} has an area of  {2:0.#}", lengthOfRectangle, breadthOfRectangle, areaOfRectangle));
  /*
  Now call the method which calculates the perimeter of the
  rectangle using the length and breadth the user has input.
  We call the method and pass the radius as a parameter
  */
  PerimeterOfRectangle(lengthOfRectangle, breadthOfRectangle);
  } // End of AreaOfRectangle method
Listing 13-83

Call the PerimeterOfRectangle() method

  1. 26.

    Click the File menu.

     
  2. 27.

    Choose Save All.

     
  3. 28.

    Click the Debug menu.

     
  4. 29.

    Choose Start Without Debugging.

     
The console window will appear and ask the user to input the radius of the circle.
  1. 30.

    Type 10 and press the Enter key.

     
The console window will ask the user to input the length of the rectangle.
  1. 31.

    Type 10.5 and press the Enter key.

     
The console window will ask the user to input the breadth of the rectangle.
  1. 32.

    Type 20.5 and press the Enter key.

     
The console window, as shown in Figure 13-24, displays the perimeter of the rectangle.

A console window depicts a perimeter of 62 below other rectangle and circle measurements post-Perimeter Of Rectangle parentheses method call.

Figure 13-24

PerimeterOfRectangle() method called and working

  1. 33.

    Press the Enter key to close the console window.

     

Chapter Summary

So, finishing this chapter on classes, we should remember what was covered in Chapter 12 on methods, because the two concepts are highly connected. Classes contain methods and fields, and we have created classes to hold methods and fields and have created separate classes when necessary, so that each class represents related items. We can access classes from the Main() method of another class, and in doing this we create a copy of the class. We use this instance, the copy of the class, to give us access to the methods and properties of the class.

We have come a long way from Chapter 1, and getting to this stage, where we can create and use our own classes, is an absolutely fantastic achievement for us in our learning. We are making fantastic progress in our programming of C# applications and we should be very proud of our achievements. In finishing this very important chapter, we have increased our knowledge further, and we are advancing to our target.

An illustration of concentric circles with two differently colored regions above a text that reads Our target is getting closer.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.209.59