Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Generic Classes

0.00/5 (No votes)
18 Jan 2010 1  
Microsoft .NET Generic classes.

Introduction

Generics is a familiar concept for most developers using .NET. But every so often, the concept of generic classes is slipping through in most application designs. The generic list is a key feature in .NET and developers tend to use it in almost every custom collection. But why not use generic classes as well? The following sections will give you an overall understanding about generic classes, and most probably, it will help you increase the usage of generic classes in your applications wherever necessary.

Creating a Generic Class

We will create a generic class to hold Number values. This class can be extended later to hold any type of numbers, e.g., int, decimal, or double. Therefore, T can be any type of number.

public class Number<T> {
    public void AddToCollection(T value) {
    }
}

And then, you can extend the class to other type of numbers like int or double, as shown in the following example:

public class DecimalNumber : Number<double> {
    public DecimalNumber() {
    }
}

The advantage is that it will give you the exact object type, thus eliminating the type casting.

Generic Class with Multiple Generic Types

You can even create a class with multiple generic types. This will benefit you when you want to create a collection of generic types in a single base class.

Generic Class with a Generic Property

You can create generic classes with generic properties using the where and new keywords. The following example is a class inherited/implemented from the DataModelBase and ILogicBase class and interface, respectively. By using a where clause, we can specify the type (T) which needs to be the property type. The new keyword creates an instance of the DataModelBase class by default if no specific type has been provided for T. The type T must be inherited from the DataModelBase class.

public class LogicBase<T> : ILogicBase
                  where T : DataModelBase, new() {
    private T _Model = default(T);
    public T Data {
        get {
            if (_Model == null) {
                _Model = new T();
            }
            return _Model;
        }
        set { _Model = value; }
    }
}

So for the implementation of the above code, first, we have to create a CustomerData class by inheriting DataModelBase and CustomerLogic, by inheriting the LogicBase class as shown below.

As you can see from the following code block, the CustomerLogic class has a CustomerData object as a property. By using the following pattern, we can increase the application extendibility:

Generic Classes in Real World

You can drastically increase the extendibility of an application design by using generic classes and make it easy to maintain. Let's take a look at the following scenario and see how we can achieve this using generic classes.

Saving a customer record into a database: There are certain classes we need to define in order to create a customer record in the database. So for the initial design, we'll create a generic LogicBase class where the T type is the ValidationBase class. ValidatioBase -- this class is responsible for all the business related validations. The following code block will show you the syntax for the LogicBase and ValidationBase classes.

public class ValidationBase {
    public virtual bool IsValidName(string name) {
        return name.Length > 5;
    }
}

public class LogicBase where T : ValidationBase, new() {
    private T _Validations = default(T);
    public T Validations {
        get {
            if (_Validations == null) {
                _Validations = new T();
            }
            return _Validations;
        }
        set { _Validations = value; }
    }
}

Now, we'll create a CustomerClass by inheriting the LogicBase class and use its IsValidName method to do business validation.

public class Customer : LogicBase<ValidationBase> {
    public void SaveCustomer(string name) {
        if (Validations.IsValidName(name)) {
            //Save Customer
        }
    }
}

As you can see in the preceding code block, we have used ValidationBase to validate the name. To have customer specific validations, let us create a CustomerValidation class by inheriting from the ValidationBase class.

public class CustomerValidation : ValidationBase {
    public override bool IsValidName(string name) {
        return name.Length > 10 ;
    }

    public bool IsValidCustomer() {
        //Write validation logic
        return true;
    }
}

You can use the CustomerValidation class to write only the customer specific validations. Modify the Customer class to use the CustomerValidation class as shown below:

Here, you will get all the customer validation methods without casting to a CustomerValidation type.

Conclusion

By using generic classes, you can significantly increase the application design and extendibility. However, you must thoroughly analyse the classes before extending to a generic class. This will eliminate unnecessary complexity in the class structure. The same behavior can be achieved using some of the Design Patterns, but it requires type casting or Reflection. So by using generic classes, you can eliminate the hassle of type casting to some extent.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here