Post

C# - Contoso Pets adoption C# console application 2

Introduction

In this post, we will continue to develop the Contoso Pets adoption console application. We will add details for the dog search and suggested donation features.

  • Dog attribute search
    • Gather input for the pet characteristic search term
    • Loop through the animals array and identify “dogs”
    • For each dog, combine the physical and personality descriptions to search
    • Search the combined description for the input term match
    • Output the dogs that have a term match
  • Suggested donation data
    • Define suggestedDonation string
    • Expand the ourAnimals array to contain suggestedDonation and populate sample data for suggestedDonation
    • Ensure all usage of ourAnimals array accounts for the added suggestedDonation data
    • Output suggestedDonation with regional currency symbol ($, €, ¥,… )

Starter code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// #1 the ourAnimals array will store the following:
string animalSpecies = "";
string animalID = "";
string animalAge = "";
string animalPhysicalDescription = "";
string animalPersonalityDescription = "";
string animalNickname = "";

// #2 variables that support data entry
int maxPets = 8;
string? readResult;
string menuSelection = "";

// #3 array used to store runtime data, there is no persisted data
string[,] ourAnimals = new string[maxPets, 6];

// #4 create sample data ourAnimals array entries
for (int i = 0; i < maxPets; i++)
{
    switch (i)
    {
        case 0:
            animalSpecies = "dog";
            animalID = "d1";
            animalAge = "2";
            animalPhysicalDescription = "medium sized cream colored female golden retriever weighing about 45 pounds. housebroken.";
            animalPersonalityDescription = "loves to have her belly rubbed and likes to chase her tail. gives lots of kisses.";
            animalNickname = "lola";
            break;

        case 1:
            animalSpecies = "dog";
            animalID = "d2";
            animalAge = "9";
            animalPhysicalDescription = "large reddish-brown male golden retriever weighing about 85 pounds. housebroken.";
            animalPersonalityDescription = "loves to have his ears rubbed when he greets you at the door, or at any time! loves to lean-in and give doggy hugs.";
            animalNickname = "gus";
            break;

        case 2:
            animalSpecies = "cat";
            animalID = "c3";
            animalAge = "1";
            animalPhysicalDescription = "small white female weighing about 8 pounds. litter box trained.";
            animalPersonalityDescription = "friendly";
            animalNickname = "snow";
            break;

        case 3:
            animalSpecies = "cat";
            animalID = "c4";
            animalAge = "3";
            animalPhysicalDescription = "Medium sized, long hair, yellow, female, about 10 pounds. Uses litter box.";
            animalPersonalityDescription = "A people loving cat that likes to sit on your lap.";
            animalNickname = "Lion";
            break;

        default:
            animalSpecies = "";
            animalID = "";
            animalAge = "";
            animalPhysicalDescription = "";
            animalPersonalityDescription = "";
            animalNickname = "";
            break;

    }

    ourAnimals[i, 0] = "ID #: " + animalID;
    ourAnimals[i, 1] = "Species: " + animalSpecies;
    ourAnimals[i, 2] = "Age: " + animalAge;
    ourAnimals[i, 3] = "Nickname: " + animalNickname;
    ourAnimals[i, 4] = "Physical description: " + animalPhysicalDescription;
    ourAnimals[i, 5] = "Personality: " + animalPersonalityDescription;

}

// #5 display the top-level menu options
do
{
    // NOTE: the Console.Clear method is throwing an exception in debug sessions
    Console.Clear();

    Console.WriteLine("Welcome to the Contoso PetFriends app. Your main menu options are:");
    Console.WriteLine(" 1. List all of our current pet information");
    Console.WriteLine(" 2. Display all dogs with a specified characteristic");
    Console.WriteLine();
    Console.WriteLine("Enter your selection number (or type Exit to exit the program)");

    readResult = Console.ReadLine();
    if (readResult != null)
    {
        menuSelection = readResult.ToLower();
    }

    // use switch-case to process the selected menu option
    switch (menuSelection)
    {
        case "1":
            // list all pet info
            for (int i = 0; i < maxPets; i++)
            {
                if (ourAnimals[i, 0] != "ID #: ")
                {
                    Console.WriteLine();
                    for (int j = 0; j < 6; j++)
                    {
                        Console.WriteLine(ourAnimals[i, j]);
                    }
                }
            }
            Console.WriteLine("\n\rPress the Enter key to continue");
            readResult = Console.ReadLine();

            break;

        case "2":
            // Display all dogs with a specified characteristic
            Console.WriteLine("\nUNDER CONSTRUCTION - please check back next month to see progress.");
            Console.WriteLine("Press the Enter key to continue.");
            readResult = Console.ReadLine();
            break;

        default:
            break;
    }

} while (menuSelection != "exit");

Add suggested donation data

  • The added donation features require you to
    • create suggestedDonation variable, and
    • to expand the ourAnimals array accommodate the new donation data.
  • Also, you need to add the suggested donation amounts for each animal, and implement a default amount when there suggested donation information is missing.
  1. Create the suggestedDonation variable below the declaration for animalNickname.

    1
    
    string suggestedDonation = "";
    
    • Update ourAnimals array to hold 7 “columns” of data for each animal instead of 6.
    1
    
    string[,] ourAnimals = new string[maxPets, 7];
    
  2. Add suggestedDonation amounts to the sample data

    • The following is code that defines sample data for the first pet before the suggestedDonation data is created. It would fit nicely below the animalNickname!
    1
    2
    3
    4
    5
    6
    7
    8
    
    case 0:
        animalSpecies = "dog";
        animalID = "d1";
        animalAge = "2";
        animalPhysicalDescription = "medium sized cream colored female golden retriever weighing about 45 pounds. housebroken.";
        animalPersonalityDescription = "loves to have her belly rubbed and likes to chase her tail. gives lots of kisses.";
        animalNickname = "lola";
        break;
    
  3. Insert a suggestedDonation value above the break statement for case 0; through default: with the following values:

1
2
3
4
5
Case 0: suggestedDonation = "85.00";
Case 1: suggestedDonation = "49.99";
Case 2: suggestedDonation = "40.00";
Case 3: suggestedDonation = "";
default: suggestedDonation = "";

Data validation with TryParse()

  • The variable suggestedDonation is intended to be a numeric value, but is collected and stored as a string.
  • In the future you may have to validate suggestedDonation represents a decimal, and that you can convert it to a decimal so it’s available to use for billing calculations.
  • To avoid an error trying to use an entry like twenty you need to use TryParse validation.
  • The code samples in this exercise are designed based on en-US culture settings, and use a period (.) as the decimal separator.
  • Building and running the code with a culture setting that uses a different decimal separators (such as a comma ,) may give unexpected results or errors.
  • To fix this issue, replace the period decimal separators in the code samples with your local decimal separator (such as ,).
  • Alternatively, to run a program using the en-US culture setting, add the following code to the top of your program: using System.Globalization; and after any other using statements add CultureInfo.CurrentCulture = new CultureInfo("en-US");.
  • This is a "minimal viable product" (MVP) feature.

Minimal Viable Product (MVP)

  • A MVP feature is intended to be a simple working prototype of a feature that enables quick and easy delivery.
  • A MVP is not usually a final product, it is intended to help you work through an idea, test it, and gather further requirements.
  • The search feature prompts the user for a single search input term (or phrase) that describes a characteristic desired in a pet to adopt.
  • Then, the descriptions for adoptable dogs are searched for exact matches of the user input.
  • Information about the dogs that match are output to the console.
  • If no matches are identified, then a message “None of our dogs are a match” is displayed along with the search term used.
  • The tasks that you complete are:
    • Gather user input for the pet characteristic search term
    • Loop through the animals array and identify “dogs”
    • For each dog, search the pet description for a term match
    • Display the dogs that have a term match
  1. Gather user input for the pet characteristic search

    • Delete the code Console.WriteLine("\nUNDER CONSTRUCTION - please check back next month to see progress."); between case "2": and the Console.WriteLine("Press the Enter key to continue."); statement so the code matches the following sample:
    1
    2
    3
    4
    5
    
    case "2":
    // Display all dogs with a specified characteristic
    Console.WriteLine("Press the Enter key to continue.");
    readResult = Console.ReadLine();
    break;
    
  2. Add code to gather user input for the dogCharacteristic string.

    • Gather the input requires a while loop that continues to prompt the user until they submit an input.
    • The loop instructs the user to “Enter one desired dog characteristic to search for”.
    • Entering an empty string repeats the loop.
    • Place the following code following case "2": just before the break; statement as shown:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    
    case "2":
     // Display all dogs with a specified characteristic
     string dogCharacteristic = "";
    
     while (dogCharacteristic == "")
     {
         // have the user enter physical characteristics to search for
         Console.WriteLine($"\nEnter one desired dog characteristics to search for");
         readResult = Console.ReadLine();
         if (readResult != null)
         {
             dogCharacteristic = readResult.ToLower().Trim();
         }
     }
     Console.WriteLine("Press the Enter key to continue.");
     readResult = Console.ReadLine();
     break;
    
    • The code starts with a string declaration string dogCharacteristic = “”; that is scoped to case “2”:. You won’t be able to utilize dogCharacteristic anywhere outside of the case statement code.
    • After Console.ReadLine() gathers user input as dogCharacteristic it ensures value isn’t null, and sets the string to lowercase and trims the surrounding spaces.
    • If dogCharacteristic has a null value, then the loop repeats gathering input.
  3. Identify which animals are dogs

    • At the end of case “2” code, just before the code Console.WriteLine(“\n\rPress the Enter key to continue”);, which is before the break;, add the following code:
    1
    2
    3
    4
    5
    6
    7
    8
    
    // #6 loop through the ourAnimals array to search for matching animals
     for (int i = 0; i < maxPets; i++)
     {
         if (ourAnimals[i, 1].Contains("dog"))
         {
             // #7 Search combined descriptions and report results
         }
     }
    
    • The code filters for “dogs” using ourAnimals[i,1], where animalSpecies data is stored.
    • If animalSpecies is storing “dog” then the code moves into the brackets of the if statement where the search of the combined descriptions can occur.
  4. Search the combined description information of dogs

    • The previous code ensures that you search only dog descriptions.
    • Now you need to search the dog descriptions and output information about matches.
    • While thinking about the descriptions, you realize there are two descriptions animalPhysicalDescription and animalPersonalityDescription;.
    • After consulting, the team decides that a combined description is appropriate for the search.
    • Some developers refer to the addition of requirements during development as "scope creep."
    • Although combining the descriptions is not a lot of work, it still adds time and complexity.
    • For this reason, you should let the team know that added requirements will likely delay the completion of the project.
    • You need to declare a string, dogDescription to hold the combined data that originated from animalPhysicalDescription and animalPersonalityDescription;.

      • Declare dogDescription just before comment #6 with the following code:
      1
      
      string dogDescription = "";
      
      • Now you can use the dogDescription string declared you need to populate it with the two descriptions for each animal
      • Using the dogDescription variable populate it with animalPhysicalDescription and animalPersonalityDescription;.
      • Add the following code after comment # 7:

        1
        2
        
        dogDescription = ourAnimals[i, 4] + "\n" + ourAnimals[i, 5];
        
        
  5. Search the combined descriptions of dogs and display

    • Now you add the search for dogCharacteristic in the combined data of dogDescription. You need to add an if statement to determine if you have a match for the search for each dog.
    • Update the code following comment #7, after dogDescription = ourAnimals[i, 4] + “\n” + ourAnimals[i, 5]; with the code:
    1
    2
    3
    4
    5
    
     if (dogDescription.Contains(dogCharacteristic))
     {
         Console.WriteLine($"\nOur dog {ourAnimals[i, 3]} is a match!");
         Console.WriteLine(dogDescription);
     }
    
    • Add the code noMatchesDog = true:
    • Add the following code just before comment #6:

      1
      
      bool noMatchesDog = true;
      
    • Now you can track when no matches are found with this tracking variable. When the default is set to true that means “it’s true that no dogs match for the search.” Now, when a dog is found you can “flip” the noMatchesDog from true to false
    • In the brackets of the if (dogDescription.Contains(dogCharacteristic)) statement, add the following code:

      1
      
      noMatchesDog = false;
      
    • The whole code block should look like this:
    1
    2
    3
    4
    5
    6
    7
    
    if (dogDescription.Contains(dogCharacteristic))
    {
        Console.WriteLine($"\nOur dog {ourAnimals[i, 3]} is a match!");
        Console.WriteLine(dogDescription);
    
        noMatchesDog = false;
    }
    
    • At the end of case “2” code, just before the code Console.WriteLine(“\n\rPress the Enter key to continue”);, which is before the break;, add the following code:
    1
    2
    3
    4
    
     if (noMatchesDog)
     {
         Console.WriteLine("None of our dogs are a match found for: " + dogCharacteristic);
     }
    
  • Run your project code in the terminal with dotnet run.
  • When the code runs two menu items are displayed.
  • At the menu, enter “2” and “Enter” to test the dog search repeatedly.
1
2
3
4
- Enter nothing as input to test the null entry behavior
 - Enter "scuba" as input to test the "match not found"
 - Enter "golden" to get two matches
 - Enter "medium" to get one match
  • If everything worked as expected in both steps, congratulations!

Final code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
// using System;

// #1 the ourAnimals array will store the following:
string animalSpecies = "";
string animalID = "";
string animalAge = "";
string animalPhysicalDescription = "";
string animalPersonalityDescription = "";
string animalNickname = "";
string suggestedDonation = "";

// #2 variables that support data entry
int maxPets = 8;
string? readResult;
string menuSelection = "";
decimal decimalDonation = 0.00m;

// #3 array used to store runtime data, there is no persisted data
string[,] ourAnimals = new string[maxPets, 7];

// #4 create sample data ourAnimals array entries
for (int i = 0; i < maxPets; i++)
{
    switch (i)
    {
        case 0:
            animalSpecies = "dog";
            animalID = "d1";
            animalAge = "2";
            animalPhysicalDescription = "medium sized cream colored female golden retriever weighing about 45 pounds. housebroken.";
            animalPersonalityDescription = "loves to have her belly rubbed and likes to chase her tail. gives lots of kisses.";
            animalNickname = "lola";
            suggestedDonation = "85.00";
            break;

        case 1:
            animalSpecies = "dog";
            animalID = "d2";
            animalAge = "9";
            animalPhysicalDescription = "large reddish-brown male golden retriever weighing about 85 pounds. housebroken.";
            animalPersonalityDescription = "loves to have his ears rubbed when he greets you at the door, or at any time! loves to lean-in and give doggy hugs.";
            animalNickname = "gus";
            suggestedDonation = "49.99";
            break;

        case 2:
            animalSpecies = "cat";
            animalID = "c3";
            animalAge = "1";
            animalPhysicalDescription = "small white female weighing about 8 pounds. litter box trained.";
            animalPersonalityDescription = "friendly";
            animalNickname = "snow";
            suggestedDonation = "40.00";
            break;

        case 3:
            animalSpecies = "cat";
            animalID = "c4";
            animalAge = "";
            animalPhysicalDescription = "";
            animalPersonalityDescription = "";
            animalNickname = "lion";
            suggestedDonation = "";

            break;

        default:
            animalSpecies = "";
            animalID = "";
            animalAge = "";
            animalPhysicalDescription = "";
            animalPersonalityDescription = "";
            animalNickname = "";
            suggestedDonation = "";
            break;

    }

    ourAnimals[i, 0] = "ID #: " + animalID;
    ourAnimals[i, 1] = "Species: " + animalSpecies;
    ourAnimals[i, 2] = "Age: " + animalAge;
    ourAnimals[i, 3] = "Nickname: " + animalNickname;
    ourAnimals[i, 4] = "Physical description: " + animalPhysicalDescription;
    ourAnimals[i, 5] = "Personality: " + animalPersonalityDescription;

    if (!decimal.TryParse(suggestedDonation, out decimalDonation)){
        decimalDonation = 45.00m; // if suggestedDonation NOT a number, default to 45.00
    }
    ourAnimals[i, 6] = $"Suggested Donation: {decimalDonation:C2}";
}

// #5 display the top-level menu options
do
{
    // NOTE: the Console.Clear method is throwing an exception in debug sessions
    Console.Clear();

    Console.WriteLine("Welcome to the Contoso PetFriends app. Your main menu options are:");
    Console.WriteLine(" 1. List all of our current pet information");
    Console.WriteLine(" 2. Display all dogs with a specified characteristic");
    Console.WriteLine();
    Console.WriteLine("Enter your selection number (or type Exit to exit the program)");

    readResult = Console.ReadLine();
    if (readResult != null)
    {
        menuSelection = readResult.ToLower();
    }

    // use switch-case to process the selected menu option
    switch (menuSelection)
    {
        case "1":
            // list all pet info
            for (int i = 0; i < maxPets; i++)
            {
                if (ourAnimals[i, 0] != "ID #: ")
                {
                    Console.WriteLine();
                    for (int j = 0; j < 7; j++)
                    {
                        Console.WriteLine(ourAnimals[i, j].ToString());
                    }
                }
            }
            Console.WriteLine("\n\rPress the Enter key to continue");
            readResult = Console.ReadLine();

            break;

        case "2":
            // Display all dogs with a specified characteristic");

            string dogCharacteristic = "";

            while (dogCharacteristic == "")
            {
                // have the user enter physical characteristics to search for
                Console.WriteLine($"\nEnter one desired dog characteristics to search for");
                readResult = Console.ReadLine();
                if (readResult != null)
                {
                    dogCharacteristic = readResult.ToLower().Trim();
                }
            }

            bool noMatchesDog = true;
            string dogDescription = "";

            // #6 loop through the ourAnimals array to search for matching animals
            for (int i = 0; i < maxPets; i++)
            {
                bool dogMatch = true;

                if (ourAnimals[i, 1].Contains("dog"))
                {

                    if (dogMatch == true)
                    {
                        // #7 Search combined descriptions and report results
                        dogDescription = ourAnimals[i, 4] + "\n" + ourAnimals[i, 5];


                        if (dogDescription.Contains(dogCharacteristic))
                        {
                            Console.WriteLine($"\nOur dog {ourAnimals[i, 3]} is a match!");
                            Console.WriteLine(dogDescription);

                            noMatchesDog = false;
                        }
                    }
                }
            }

            if (noMatchesDog)
            {
                Console.WriteLine("None of our dogs are a match found for: " + dogCharacteristic);
            }

            Console.WriteLine("\n\rPress the Enter key to continue");
            readResult = Console.ReadLine();

            break;

        default:
            break;
    }

} while (menuSelection != "exit");

This post is licensed under CC BY 4.0 by the author.