Vince's Blog

Experiences and Tips on .NET Development for Business

Category: Basics

Abstract Classes and Inheritance using C# – Part 2

In Part 1, we created a base class that contains a common property in our app, UserId. Before we move on, let’s tack on some common functions we can use throughout our app. If we bundle up some lightweight methods in a Utilities class, we can attach that to our base class as a read-only property.

We can take our new class and attach it to the base class with one line of code. We’ll need to add a constructor to our Initialize method, too.

I am sure there are detractors to this approach. I like it because I can code one reference and have my functions available in any derived class. However, I only do this with lightweight classes with methods that consume simple types, structs, enums or other lightweight classes. We’ll use the functions in this example in later articles. For now, though, we will consider this our completed super class.

Let’s go to our main class library and derive a new abstract class from the LevelOneBase class. If we’re only creating another abstract, or base, class, why not just include everything in the original base class? The reason is that, by layering abstract classes, we can propagate only the functionality required by the level we are at in our class hierarchy. As an example, our program manages tasks and tracks the result of running a series of tasks. We will create a new abstract class whose role is to manage tasks and call it TaskManager.

When you follow a new declared class by a colon and another class name, the new class inherits the other class. That means we can access the UserId property without declaring it a second time and also be able to access our utility functions. Note how when parameters are provided in the constructor, the Initialize method is called rather than setting properties right in the constructor. This is done so that logic is coded once. If we add other limitations to the container size later, we only need to update the Initialize method. This also supports the requirement that the tree must pass on initialization to the base classes.

We added a TaskCollection property to the TaskManager class to hold a collection of running tasks. One of the best parts of using async and await in C# (https://msdn.microsoft.com/en-us/library/hh191443.aspx) is that you can work, not only with class objects, but with running tasks as well. In Part 3 we will create a new method that processes these tasks and also extend our class with anonymous types as a way to manage tasks with different return types using one base class and method.

Abstract Classes and Inheritance using C# – Part 1

On a recent project, I tried to make better use of inheritance to simplify coding and improve the supportability of the end product. In the C# Programming Guide, inheritance is defined as a technique that “enables you to create new classes that reuse, extend, and modify the behavior that is defined in other classes.” In my case, I was seeking out ways to code a piece of business logic once and then share it using base classes. Sometimes, the base class is not even in the same assembly as the derived class let alone in the same namespace. I also try and use access modifiers to only show functionality on a need to know basis. By only showing the meaningful set of methods and properties, it makes the next programmers job easier as the intended way to use the class is clear. It’s actually easier to show than describe, so let’s get started.

Let’s start with our base class or “super class”. This is the class that contains the properties and methods used by its offspring or derived classes. An easy property to picture being shared is a UserId property. Let’s say that most, if not all work being done in the application needs to know who the user is. This might be for security, personalization, or to have on hand for interacting with data stores. Here is our base class with the UserId property.

There are a few things to know about and a few problems with our class. As the namespace suggests, the base class will actually be contained in a different assembly than our derived class. The C# language only supports two access modifier types for classes defined at the namespace level, public and internal. The default is internal, so our new class won’t be visible outside of the NewAssembly.dll library. In addition, the base class isn’t useful as a stand alone class. This is easy to fix by using the “pubic” access modifier and “abstract” keyword. This will make the base class visible outside the assembly, but it can only be inherited, not instantiated on its own.

Now, let’s look at the UserId property. Since within a class the default access modifier is “private”, the property won’t be visible outside of the class. We would like it visible to any derived class, but not outside of the class hierarchy. In addition, we want to set the value of the property when the class is instantiated, but not allow it to be changed afterwards. To accomplish this, we can use the “protected” access modifier and change the set action to private.

This creates a new problem. How should we set the value of the UserId property? For reasons I can’t fully cover here, I have become a fan of providing a default parameterless constructor, a loaded constructor with all required parameter and an initialization method to set base values. The parameterless constructor and initialization method need to both have the same access modifier. If they were both private, it would work but the parameterless constructor is really just a placeholder as it is inaccessible outside of the class. The loaded constructor can use the same modifier or provide even more access, but not less access.

Let’s take another look at the access modifiers we’ve chosen. The base class has a “public” modifier since anything less makes the base class useless outside of the assembly. However, the constructors are “protected”. This is because initialization of the base class needs to be managed by the derived class. The derived class will likely contain a public initializer, but the base class initializer should only be visible within the class hierarchy. It’s reasonable to let users of the derived class know whether the class is initialized and what the UserId value is. Therefor, these are both public. In the next article, we’ll inherit from our new base class.

Powered by WordPress & Theme by Anders Norén