Shining Star Services LLC
C# Custom LinkedList Console Application and Abstract Base Class and Method - Learning C# - Part 1
One of the best ways to learn a new technology is by using it. In this tutorial, you will create a base class or abstract class, a derived or inherited class. You will work with self-referencing members, a constructor, if statements, for loops, null values, conditional operators, mathematical operators, relational operators, equality operators, and assignment operators. These concepts are quite basic to programming, but if you're learning, they're new to you.

In our example we will create an abstract Inventory class. The Inventory class will have two functions: Category and Item. We will create a derived class, LinkedList, that uses the Inventory class as a linked list. This class will use custom methods, not built-in methods. In the LinkedList class we will create methods to add inventory items to the linked list, as well as remove them from the top of the stack or the bottom of the stack. We will also create methods to print in forward or reverse orders. And finally, we will create a method to allow searching the list by category or item and display the search results.

First, let's create a console application. In Visual Studio, select File, New, and Project. Select the Visual C# category and the Console Application option.

Name your project CSLinkedList and the solution name CSLinkedList. If you select the checkbox to "Create directory for solution," a new directory named CSLinkedList will be created, otherwise, your solution will be put inside the Location you designate.



using System;

namespace CSLinkedList
{

At the top of our project, you will see we need one .NET component, System. That is referenced by default when your project is created. If you open up the References list in the project explorer, you will see the list of libraries that are included by default. These add .NET framework functionality to your project.



namespace has been created by default. Namespaces help organize your code and provide a way to create globally unique types.
   public abstract class Inventory
   {

   public abstract string Category();

   public string inventoryItem = string.Empty;
   public string Item()
   {
   return inventoryItem;
   }
   }

One of the key concepts of object oriented programming is Inheritance along with Abstraction. Inheritance allows you to create a class that allows you to reuse behaviors and definitions.

We first want to create a base class, Inventory. That means that it is a parent class. To make the Inventory class a base class, we use the keyword "abstract." This means any abstract methods defined in the base class must be implemented in the inherited or derived class. If you do not wish to require implementation, use the "virtual" keyword which means that the derived class "can" override the method with its own implementation, but does not have to.

In our above example, we have an abstract method "Category" and an implemented string and method: inventoryItem and Item(). Notice we do not define an implementation for the Category() method. The implementation must be defined by the derived class.
 
Our linked list will use the Item() and Category() for retrieving our Inventory item names.

In Part 2 of our series, we will setup our LinkedList derived class and define our properties and setup our constructor.

C# Custom LinkedList Derived Classes, Constructor Initializations - Learning C# - Part 2
In Part 1 of this series, we created a console application and an abstract class. In this article we will setup our LinkedList derived class and define our properties and setup our constructor.

To allow our derived class to inherit from our Inventory class, after defining the LinkedList class, we add a colon and the name of the base class "Inventory." Upon typing the word "Inventory" from the keyboard, type "Ctrl" + "." -- this key combination opens up a drop down asking you to "Implement abstract class Inventory." Select that option and your class is created with the base class overrideable methods, in this case "Category."

   public class LinkedList : Inventory
   {
   public override string Category()
   {
   throw new NotImplementedException();
   }
   }


We define a private string inventoryCategory, to hold our assigned values. When we need to retrieve these values, we use the Category method. On your own, do some research on using Get/Set Properties instead of methods.
   public class LinkedList : Inventory
   {
   // custom linked list

   private string inventoryCategory;
   public override string Category()
   {
   return inventoryCategory;
   }
   
   // self-referencing members (same name as its class)
   private LinkedList Head;   // pointer to the top of the stack
   // the last node added to the list
   private LinkedList Next;   // index to locate an item in the list

   private int size;   // how many records in the list

   public LinkedList()   // constructor / default values
   {
   Head = null;   // no items have been added 
   Next = null;
   inventoryCategory = string.Empty;
   size = 0;  // 1 based - list starts out as empty
   }


We create two self-referencing members, meaning the type is the same name as their class: "private LinkedList Head" and "private LinkedList Next". The first points to the most recent node added to the list or the top of the stack. The second points to the next node on the list that was just previously added so that we can traverse through the list. Once we traverse to the next node, it again has its own Next node, to point to the previous node, and so forth.

The "private int size" statement defines an integer used to keep track of how many records are in the list.

Next we define our constructor: "public LinkedList()." "Constructors: are class methods that are executed when an object of a class or struct is created. They have the same name as the class or struct, and usually initialize the data members of the new object."

True to our definition, we initialize the Head and Next to null. We set our inventoryCategory to empty using "string.Empty."  We could have just as easily set our inventoryCategory to empty by assigning it a value of "" (2 quote marks).

We set our size to 0. Our list will be 1 based and increment to 1 when the first node is added.

In Part 3 of our series, we will define our Push and Pop methods.

Nannette

C# Custom LinkedList Push and Pop Methods - Learning C# - Part 3
In Part 1 of this series, we created a console application and an abstract class. In Part 2 we setup our LinkedList derived class and defined our properties and setup our constructor.

In this article, we define our Push and Pop methods. Our Push method allows us to add an Inventory item to our list on the top of the stack. We define PopLifo and PopFifo (last in first out and first in first out) methods.


   public int Push(string invCategory, string invItem)
   {
   // add the Inventory to the list
   LinkedList node = new LinkedList();
   node.inventoryCategory = invCategory;
   node.inventoryItem = invItem;
   node.Next = Head;  // set the Next pointer to the 
   // last item previously added
   Head = node;   // set the Head as the item just now added
   return size++;  // increment the size of the list
   }


We create our Push method as public, and it returns the size of our list as an integer. We pass two parameters to our method: the category and item.

In our first statement, we create a new "node." Since we are making it a LinkedList type, that means it consists of its own category, item, and Next value. In our next statement, as we type the word "node." intellisense provides the different properties defined in the LinkedList, thus allowing us to easily populate these items. We set our node.inventoryCategory value, etc.

Our node.Next is assigned to our previously added node as stored in "Head." And our Head node is reassigned with the values we just entered.

We increment our size counter and return the value.

In our Pop methods, we aren't actually "deleting" anything. Let's take a look:


   public void PopLifo()   // LIFO
   {
   if (size > 0)
   {
   LinkedList node = Head;
   Head = node.Next;   // assign pointer to the head to the previous second node
   size--;   // decrement the counter
   }
   }

In our PopLifo method, we remove the last node added to the list. To do so, we first want to see if our size is greater than zero, using the ">" relational operator. If so, we create a new node and assign it to our "Head." We then reassign our Head, or top of the list, to point to the node that Head was pointing to, our "node.Next." Then we decrement our size of our list.

   public void PopFifo()
   {
   if (size > 0)   // don't allow to keep decrementing counter if list is empty
   size--;   // decrement the counter to remove it from displaying in the list (won't traverse to this node)
   }

Removing our node from the "first in" node on the list is much simpler. We simply decrement our size by one so that when we traverse through the nodes we never hit it.

In Part 4 of our series we will Print our list to the screen.

Nannette


C# Custom LinkedList PrintLifo method and C# Operators - Learning C# - Part 4
In Part 1 of this series, we created a console application and an abstract class. In Part 2 we setup our LinkedList derived class and defined our properties and setup our constructor. In Part 3, we defined our Push and Pop methods. We implemented both a PopLifo and PopFifo method.

In this article, we define our PrintLifo method to print nodes from the top of the stack. We will also define a PrintFifo method, which will use a GetNode helper method to find specific nodes, allowing us to print nodes from the bottom of the stack.


   public void PrintLifo()
   {
   LinkedList node = Head;
   for (int i = size; i > 0 && node != null; i--)
   {
   Console.WriteLine("Category: {0} Item: {1}",
   node.Category(), node.Item());
   node = node.Next;
   }
   }


In our above PrintLife() method, we create a new node, and assign it to our existing Head node. We will use a for statement to loop through our nodes, finding the previous node by using the "node.Next" value.

   for (int i = size; i > 0 && node != null; i--)


In our "for" loop, we define a new integer value "i" and set it to the size of our linked list. We then loop as long as "i" is greater than 0 and the node is not null or empty. On each loop we decrement our counter with "i--." In this one statement we are making use of assignment operators: i = size and i--. We are also using the relational operator ">" to see if "i" is greater than 0. And we are using the equality operator "!=" to see if the node is null or not.

C# uses several such operators. Think of the word: CREAM.
Conditional Operators &&, ||
Relational Operators  <, >, <=, >=
Equality Operators ==, !=
Assignment Operators =, +=, -=, *=, /=
Mathematical Operators +, -, *, /

In our next article we will print our linked list in first in first out order and create a helper method GetNode() which allows us to retrieve a specific node by position.

Nannette

C# Custom LinkedList PrintFifo method and GetNode by Position - Learning C# - Part 5
In Part 1 of this series, we created a console application and an abstract class. In Part 2 we setup our LinkedList derived class and defined our properties and setup our constructor. In Part 3, we defined our Push and Pop methods. We implemented both a PopLifo and PopFifo method. In part 4 we defined our PrintLifo method to print nodes from the top of the stack. We also discussed C# Operators.

In this article we will define a PrintFifo() method, which will use a GetNode() helper method to find specific nodes, allowing us to print nodes from the bottom of the stack.

To print our list in "first in first out" order, since our linked list contains pointers to the previously added node on the list, we have no direct means to access the first node on the list, so we will create a "GetNode()" method to find a specific node by position.


   private LinkedList GetNode(int position)
   {
   // traverse thru list until reach the node at the position passed in
   // loop until reach the position just before the position desired, 
   // and return the .Next node, which is the position desired

   LinkedList node = Head;  // start with the last item added
   for (int i = 1; i < position && node != null; i++)
   node = node.Next;
   return node;
   }


Our GetNode method will return a LinkedList at the position passed in as a parameter. We create a new node, which we assign to the Head node. Then we loop, beginning at 1, until 1 is greater than the position passed in or our node is not null, and we increment our counter as we loop through nodes. With each loop, we reassign our node to the node stored in the node.Next. Once we hit the node just prior to the position desired, we assign our node to the node.Next value -- which is the desired node -- and we return our node.


   public void PrintFifo()
   {
   for (int i = size; i > 0; i--)
   {
   LinkedList node = this.GetNode(i);
   Console.WriteLine("Category: {0} Item: {1}",
   node.Category(), node.Item());
   }
   }


Now we are ready to use the GetNode() method in our PrintFifo() method to print our list in "first in first out" order. Again, we use a "for" loop to loop through the nodes beginning with the node at the bottom of the stack -- the one in our linked list "size." We create a new node and assign it to the value returned from GetNode(i).

We then utilize the Console.WriteLine() method to print our values to the screen. Utilizing {0} {1} etc. allows us to leave a placeholder for the values following the string you want printed. In our example, the category name retrieved from the node.Category() method will print in the {0} position and the value retrieved from the node.Item() method wil print in the {1} position.

In our next article, we will create a FindItems() method which will print a listing to the screen of all items based on the category or item name.

Nannette


C# Custom LinkedList FindItems() method - Learning C# - Part 6
In Part 1 of this series, we created a console application and an abstract class. In Part 2 we setup our LinkedList derived class and defined our properties and setup our constructor. In Part 3, we defined our Push and Pop methods. We implemented both a PopLifo and PopFifo method. In part 4 we defined our PrintLifo method to print nodes from the top of the stack. We also discussed C# Operators. In Part 5 we defined a PrintFifo() method, which used a GetNode() helper method to find specific nodes, allowing us to print nodes from the bottom of the stack.

In this article, we will create a FindItems() method which will print a listing to the screen of all items based on the category or item name.


   public bool FindItems(string category, string item = "")
   {
   LinkedList CurrentNode = new LinkedList();
   bool boolSuccess = false;   // initialize

   if (category == "" && item == "")
   {
   Console.WriteLine("\nYou must provide a category or item to begin the search.");
   return boolSuccess;
   }
First we define our FindItems method and pass the category by name. Our "item" parameter is an optional parameter, indicated so by defining the default value: '= ""'. This means that the user may pass in a value or not use it at all as in: FindItems(categoryname,itemname) vs. FindItems(categoryname).

If our category and our item are both blank, we send a message to the screen and return to the calling method. If not, we write a message to the screen indicating that we are in search mode and what the two search criteria are.

   Console.WriteLine("\nSearch Criteria: '{0}' and '{1}'\n", category, item);

   for (CurrentNode = Head; CurrentNode != null; CurrentNode = CurrentNode.Next)
   {
   // if it finds the item or the category, print the item
   if ((CurrentNode.Item() == item) ||
   (CurrentNode.Category() == category))
   {
   Console.WriteLine("Found Category: {0} Item: {1}", CurrentNode.Category(), CurrentNode.Item());
   boolSuccess = true;
   }
   }
   return boolSuccess;
   }

}


In this "for" loop, we start with the Head node, and as long as the node is not null, we loop through the nodes, reassigning our current node to the node as stored in the "Next" node. As we loop through the nodes, we see if the value of the item or category match the search criteria, and if so, we print the node values to the screen. If an item is found, we set the boolSuccess value to true and at the end of the method, we pass this back to the calling method.

In our next article, we will look at our Main() program and how to use our new LinkedList class.

Nannette

C# Custom LinkedList Main() method - Learning C# - Part 7
In Part 1 of this series, we created a console application and an abstract class. In Part 2 we setup our LinkedList derived class and defined our properties and setup our constructor. In Part 3, we defined our Push and Pop methods. We implemented both a PopLifo and PopFifo method. In part 4 we defined our PrintLifo method to print nodes from the top of the stack. We also discussed C# Operators. In Part 5 we defined a PrintFifo() method, which used a GetNode() helper method to find specific nodes, allowing us to print nodes from the bottom of the stack. In Part 6 we created a FindItems() method which printed a listing to the screen of all items based on the category or item name.

In this final article, we will look at our Main() program and how to use our new LinkedList class.

   class Program
   {
   static void Main(string[] args)
   {

   LinkedList ListItems = new LinkedList();
   ListItems.Push("Kitchen", "Dining Room Set");
   ListItems.Push("Living Category", "Sofa and Recliner");
   ListItems.Push("Living Category", "Stereo and Sound System");
   ListItems.Push("Electronics", "PS3");
   ListItems.Push("Electronics", "Wii");
   ListItems.Push("Electronics", "Nook");
   ListItems.Push("Electronics", "Big Screen TV");
   ListItems.PrintFifo();
   Console.WriteLine("Pop");
   ListItems.PopFifo();
   ListItems.PopLifo();
   ListItems.PrintLifo();
   ListItems.FindItems("Electronics");
   Console.ReadLine();
   }
   }
}


When we create a console application, our Program class and Main() method are setup by default. Our Main() method is defined as a static method. The "static" keyword instructs the system to create only one instance of the method regardless of how many instances of its class are created.

In our Main() method, we create a new LinkedList and name it ListItems. Rather than using this to create nodes, as we did with the Head and Next nodes which were also LinkedLists, we are going to use this to call the methods defined in the LinkedList class. When we type "ListItems." intellisense will kick in and display all public methods defined in our LinkedList class. Now we can use this to Push() inventory items to our list, PrintFifo() or PrintLifo(), PopFifo() or PopLifo(), and FindItems(). We want to follow up with Console.ReadLine(); to keep the text from zooping off the screen and returning to the program. Console.ReadLine(); will allows us to stop and wait for input, thus allowing us to see our results.




In our example above, we print our items in LIFO order, then we remove the top and bottom nodes, then print our remaining items in FIFO order. Then we search for items in the "Electronics" category and display them to the screen. Play around with it, put in break points and step through the code and see what is happening. And be sure to try the PrintFifo() method as well!

Nannette


Download Source Code and Links to WebBlog
© Copyright 1997-2019 Shining Star Services LLC, Nannette Thacker. All Rights Reserved.