Use Generics to Create an Audit Trail

Use Generics to Create an Audit Trail

he Whidbey release of .NET will include a new Common Language Runtime (CLR) feature called generics. Generics allow you to use a variable to represent a desired data type, and thereby create very generic code (hence the name) that works with any data type.

You define the data type for the generic variable at run time and the CLR substitutes that data type for the variable everywhere in the code that it is used; basically providing you with strongly typed generic code.

Understanding Generics
Generics provide for multiple levels of abstraction, which can make them somewhat difficult to get your head around. So before I show you how to use generics in a more complex “real-world” application, it’s best to start with a simple example using structures.

Structures provide a straightforward mechanism for defining a set of related properties and methods. For example, a point consists of an x-value and a y-value, represented by two properties in a point structure.

You could use a structure to define a value with properties for the old value and the new value. If you wanted your value structure to support multiple data types, such as string, integers, and so on, you need to define a different structure for each data type.

In Visual Basic .NET:

' Without generics   Public Structure StringValues      Public sOldValue As String      Public sNewValue As String   End Structure   Public Structure IntValues      Public iOldValue As Int32      Public iNewValue As Int32   End Structure

In C#:

// Without generics   public struct StringValues   {      public string sOldValue;      public string sNewValue;   }   public struct IntValues   {      public int iOldValue;      public int iNewValue;   }

This can be unwieldy, especially if you have many different data types that you need to support.

With generics, you can create one set of code and use a variable to represent the desired type. You define the generic type using the Of keyword in Visual Basic .NET and the angle bracket (< >) symbols in C#:

You define the generic type using the Of keyword in Visual Basic .NET and the angle bracket (< >) symbols in C#.

In Visual Basic .NET “Whidbey”:

' With generics   Public Structure Values(Of T)      Public OldValue As T      Public NewValue As T   End Structure

In C# .NET “Whidbey”:

// With generics   public struct Values   {      public T OldValue;      public T NewValue;   }

One structure then supports any type of data. You define the desired data type when you create the structure:

In Visual Basic .NET “Whidbey”:

Dim a As New Values(Of String)   a.OldValue = ""   a.NewValue = "Generics Test"   Dim b As New Values(Of Int32)   b.OldValue = 0   b.NewValue = 10

In C# .NET “Whidbey”:

Values a = new Values();   a.OldValue = "";   a.NewValue = "Generics Test";   Values b = new Values();   b.OldValue = 0;   b.NewValue = 10;

The first three lines in both the Visual Basic .NET and C# examples define a structure of type String and the last three lines define a structure of type Integer. The CLR replaces each reference to the generic variable T with the defined data type?providing a strongly typed structure.

Strongly typed implies that it enforces the data type at compile time. So if you attempt to set the OldValue or NewValue to anything but a String in the first example or an Integer in the second example, you will get a compile error.

Using strong typing improves the quality of your application because it minimizes the possibility of data type errors. And, since it does not have to perform boxing or data type casting, generic code performs better.

Note that in Visual Basic .NET, assigning a value of the wrong type only generates a compile-time error if you use Option Strict On in your project. Otherwise the error occurs at run time.

Building a Generic List
When your application needs to retain a set of data or objects, you can use one of the many collection-type classes provided in the .NET Framework such as Stack, Queue, and Dictionary. These classes allow you to store any type of object in the collection. In some cases this may be a good thing, such as when you want to keep a list of the last set of changed objects. In many cases, however, you want to ensure that a collection only contains objects of a particular type.

Generics provide a way to build general code that is specific at run time.

In Visual Studio .NET 2003 you can only create a strongly-typed collection class by building a collection class for each type. For example, if you want a strongly-typed collection for strings and a strongly-typed collection for integers, you would create two collection classes, one for strings and one for integers. This makes it laborious to create strongly-typed collections for many different types.

With Whidbey and generics, you can create a single collection class and define its type at run time, just like in the prior structure.

In Visual Basic .NET “Whidbey”:

Public Class List(Of ItemType)      Private elements() As ItemType   End Class

In C# “Whidbey”:

public class List   {      private T[] elements;   }

The Visual Basic .NET example defines a List class with an elements array that will only hold items of a specific type, generically represented in the example as ItemType. Likewise, the C# example defines a List class with an elements array that will only hold items of a specific type, generically represented in the example as T. In both examples, you can use any variable name to represent the generic variables shown as ItemType and T.

When you use the List class, you define the desired data type for the list.

In Visual Basic .NET “Whidbey”:

Dim intList as New List(Of Integer)   Dim strList as New List(Of String)

In C# .NET “Whidbey”:

List intList = new List();   List strList = new List();

The first line of each example creates a list of integers and the second line creates a list of strings.

You can then add code to the List class to manage the list. Every List class needs a count of the number of elements, a way to add elements, and a way to get and set element contents.

In Visual Basic .NET “Whidbey”:

Private iIndex As Integer = -1   Public Sub Add(ByVal element As ItemType)      ' Start the array out at 10      If iIndex = -1 Then         ReDim elements(10)      End If      If (iIndex = elements.Length) Then         ReDim Preserve elements(iIndex + 10)      End If      iIndex += 1      elements(iIndex) = element   End Sub   Default Public Property _        Item(ByVal index _      As Integer) As ItemType      Get         Return elements(index)      End Get      Set(ByVal Value As ItemType)         elements(index) = Value      End Set   End Property   Public ReadOnly Property Count() As Integer      Get         ' The index starts at 0, the count at 1         ' So adjust the index to the count         Return iIndex + 1      End Get   End Property

In C# .NET “Whidbey”:

private int count = -1;   public void Add(T element)   {      if (count == -1)      {         // Start with 10 elements         elements = new T[10];      }      // Increment by 10 more as needed      if (count == elements.Length)      {         elements = new T[count + 10];      }      elements[++count] = element;   }   public T this[int index]   {      get { return elements[index]; }      set { elements[index] = value; }   }   public int Count   {      get { return count; }   }

You can then add items and retrieve their contents in a strongly-typed manner. This means that value types, such as integers, won’t be boxed and won’t require casting. It also means that no one can accidentally put anything but an item of the defined type into the list.

You can use the List class to manage a list of integers:

In Visual Basic .NET “Whidbey”:

Dim intList as New List(Of Integer)   intList.Add(1)         ' No boxing   intList.Add(2)         ' No boxing   intList.Add("Three")   ' Compile-time error   Dim i As Int32 = intList(0)   ' No cast required   For j As Int32 = 0 To intList.Count       Debug.WriteLine(intList(j).ToString)   Next

In C# .NET “Whidbey”:

List intList = new List();   intList.Add(1);      // No boxing   intList.Add(2);      // No boxing   //intList.Add("Three");      // Compile-time error   int i = intList[0];   // No cast required   for (int j = 0; j <=intList.Count; j++)   {      Debug.WriteLine(intList[j]);   }

Since the List class is generic, you can also use it to manage a collection of strings:

In Visual Basic .NET "Whidbey":

Dim strList as New List(Of String)   strList.Add("This")   strList.Add("tests")   strList.Add("generics")   For j As Int32 = 0 To strList.Count       Debug.WriteLine(strList(j)) ' No cast required   Next

In C# .NET "Whidbey":

List strList = new List();   strList.Add("This");   strList.Add("tests");   strList.Add("generics");   for (int j = 0; j<=strList.Count; j++)   {      Debug.WriteLine(strList[j]); // No cast required   }

Using generics you can create one set of code that works with any data type and yet is strongly-typed at run time. And, since there are no boxing or casting operations, you also get improved performance.

Leaving an Audit Trail
Applications with critical business data often require an audit trail. Take invoicing for example. In a perfect world, an application should generate invoices for a business using input data such as time sheets, job reports, or purchase orders. There should be no need for the users to update these documents. But in the real world, there are data input errors, special customer requests, last minute discounts or uplifts, and so on. So users occasionally need to update some invoices. But do you just want any user to be able to update any invoice? (Probably not.)

In addition to building code that controls which users have access to invoicing, you can build features into the application to track which users updated which fields. This provides an auditing mechanism to answer any future questions regarding changes to the invoice.

Though these examples use invoicing, you can apply the concepts similarly to any other business entity where you want to audit changes to the data.

Here I've created an Audit class to collect the set of auditing data. It tracks what field was changed, the old value and new value, the user that made the change, and the date and time that the user made the change.

In Visual Basic .NET "Whidbey":

Public Class Audit      Private m_sPropertyName As String      Private m_sOriginalValue As String      Private m_sNewValue As String      Private m_sUserName As String _         = "Deborah"      Private m_dtAuditDate As Date   End Class

In C# .NET "Whidbey":

public class Audit   {      string m_sPropertyName="";      string m_sOriginalValue="";      string m_sNewValue ="";      string m_sUserName= "Deborah";      DateTime m_dtAuditDate =DateTime.Now;   }

Notice that the user name in both examples is hard-coded to my name. In a real application you would want to set the appropriate user's identification information. This may be the username that was used to log into the system or some ID entered into your application.

The constructor for this Audit class sets the properties based on the passed in parameters.

In Visual Basic .NET "Whidbey":

Public Sub New(ByVal sPropertyName As String, _      ByVal sOriginalValue As String, _      ByVal sNewValue As String)      m_sPropertyName = sPropertyName      m_sOriginalValue = sOriginalValue      m_sNewValue = sNewValue      m_dtAuditDate = Now   End Sub

In C# .NET "Whidbey":

public Audit(string sPropertyName,    string sOriginalValue,    string sNewValue)   {      m_sPropertyName = sPropertyName;      m_sOriginalValue = sOriginalValue;      m_sNewValue = sNewValue;      m_dtAuditDate = DateTime.Now;   }

You can expose any of the values associated with the Audit object using properties. You may want to consider making the properties read-only so they can be retrieved, but not updated.

In Visual Basic.NET "Whidbey":

Public ReadOnly Property PropertyName() _      As String      Get         Return m_sPropertyName      End Get   End Property   Public ReadOnly Property AuditDate() _      As Date      Get         Return m_dtAuditDate      End Get   End Property

In C# .NET "Whidbey":

public string PropertyName   {      get {return m_sPropertyName;}   }   public DateTime AuditDate   {      get { return m_dtAuditDate ;}   }

Each business object could include code that creates Audit objects, but by using a class factory to build the Audit objects you keep that code encapsulated. The class factory generates the Audit objects as needed. In this example, the AuditFactory class builds Audit objects only if the data changed.

In Visual Basic .NET "Whidbey":

Public Class AuditFactory(Of BOType)      Public Function Add(ByVal bo As BOType, _         ByVal sPropertyName As String, _         ByVal sNewValue As String) As Audit         Dim boPropertyInfo As _            System.Reflection.PropertyInfo = _            bo.GetType.GetProperty(sPropertyName)         Dim sOriginalValue As String = _            boPropertyInfo.GetValue(bo, Nothing).ToString         If sOriginalValue <> sNewValue Then            ' Create an audit entry            Dim oAudit As New Audit(sPropertyName, _               sOriginalValue, sNewValue)            Return oAudit         Else            Return Nothing         End If      End Function   End Class

In C# .NET "Whidbey":

public class AuditFactory   {      public Audit Add(BOType bo,          string sPropertyName, string sNewValue)      {         System.Reflection.PropertyInfo            boPropertyInfo =                typeof(BOType).GetProperty(sPropertyName);         string sOriginalValue=             (string)boPropertyInfo.GetValue(bo, null);         if (sOriginalValue != sNewValue)         {            Audit oAudit = new Audit(sPropertyName,               sOriginalValue, sNewValue);            return oAudit;         }         else         {            return null;         }      }   }

The class factory uses generics to define the type of business object that will be audited at run time. The Add method in the class factory uses reflection to get the current value of a particular property. It then compares the current value with the new value that was passed in to this method. If the value is changed then an Audit object is created and returned.

Code in the business object keeps the list of audit records. This example uses an Invoice class, though you can use any class.

In Visual Basic .NET "Whidbey":

Public Class Invoice      Dim oInvoiceAudit As New List(Of Audit)      Dim oAuditFactory As New AuditFactory(Of Invoice)      Dim oAudit As Audit      Dim m_sInvoiceDescription As String = ""         Public Property InvoiceDescription() As String         Get            Return m_sInvoiceDescription         End Get         Set(ByVal Value As String)            oAudit = oAuditFactory.Add(Me, _               "InvoiceDescription", Value)            If oAudit IsNot Nothing Then               oInvoiceAudit.Add(oAudit)            End If            m_sInvoiceDescription = Value         End Set      End Property   End Class

In C# .NET "Whidbey":

public class Invoice   {      List oInvoiceAudit =          new List();      AuditFactory oAuditFactory =          new AuditFactory();      Audit oAudit;      string m_sInvoiceDescription = "";         public string InvoiceDescription      {         get { return m_sInvoiceDescription; }         set         {            oAudit = oAuditFactory.Add(this,                "InvoiceDescription", value);            if (oAudit != null)            {               oInvoiceAudit.Add(oAudit);            }            m_sInvoiceDescription = value;         }      }   }

This code first creates a list of Audit objects. It uses the generic List class to manage the list. It then creates an instance of the AuditFactory, defining that it will create audit records for the Invoice class. An Audit object is declared but not created because the AuditFactory is responsible for creating the Audit objects.

The code for each property in the class then calls the AuditFactory, which compares the original property value and new property value to determine whether to create an Audit object. The property code shown in the examples provide a pattern that you can use to define any other properties of the class.

Generics provide a way to build general code that is specific at run time. Generics give you the best of both worlds: the efficiency of building generic code and the type safety and performance of building strongly-typed code.

The techniques shown in this article only show a small fraction of the power of generics. You can use them in interfaces and in delegates. You can specify constraints to limit the valid data types that your users can use in the generic code. You can define multiple generic types in one class. Plus, the .NET Framework provides a pre-defined set of generic collections.

devx-admin

devx-admin

Share the Post:
Renewable Storage Innovation

Innovative Energy Storage Solutions

The Department of Energy recently revealed a significant investment of $325 million in advanced battery technologies to store excess renewable energy produced by solar and

Development Project

Thrilling East Windsor Mixed-Use Development

Real estate developer James Cormier, in collaboration with a partnership, has purchased 137 acres of land in Connecticut for $1.15 million with the intention of

USA Companies

Top Software Development Companies in USA

Navigating the tech landscape to find the right partner is crucial yet challenging. This article offers a comparative glimpse into the top software development companies

Software Development

Top Software Development Companies

Looking for the best in software development? Our list of Top Software Development Companies is your gateway to finding the right tech partner. Dive in

India Web Development

Top Web Development Companies in India

In the digital race, the right web development partner is your winning edge. Dive into our curated list of top web development companies in India,

Renewable Storage Innovation

Innovative Energy Storage Solutions

The Department of Energy recently revealed a significant investment of $325 million in advanced battery technologies to store excess renewable energy produced by solar and wind sources. This funding will

Renesas Tech Revolution

Revolutionizing India’s Tech Sector with Renesas

Tushar Sharma, a semiconductor engineer at Renesas Electronics, met with Indian Prime Minister Narendra Modi to discuss the company’s support for India’s “Make in India” initiative. This initiative focuses on

Development Project

Thrilling East Windsor Mixed-Use Development

Real estate developer James Cormier, in collaboration with a partnership, has purchased 137 acres of land in Connecticut for $1.15 million with the intention of constructing residential and commercial buildings.

USA Companies

Top Software Development Companies in USA

Navigating the tech landscape to find the right partner is crucial yet challenging. This article offers a comparative glimpse into the top software development companies in the USA. Through a

Software Development

Top Software Development Companies

Looking for the best in software development? Our list of Top Software Development Companies is your gateway to finding the right tech partner. Dive in and explore the leaders in

India Web Development

Top Web Development Companies in India

In the digital race, the right web development partner is your winning edge. Dive into our curated list of top web development companies in India, and kickstart your journey to

USA Web Development

Top Web Development Companies in USA

Looking for the best web development companies in the USA? We’ve got you covered! Check out our top 10 picks to find the right partner for your online project. Your

Clean Energy Adoption

Inside Michigan’s Clean Energy Revolution

Democratic state legislators in Michigan continue to discuss and debate clean energy legislation in the hopes of establishing a comprehensive clean energy strategy for the state. A Senate committee meeting

Chips Act Revolution

European Chips Act: What is it?

In response to the intensifying worldwide technology competition, Europe has unveiled the long-awaited European Chips Act. This daring legislative proposal aims to fortify Europe’s semiconductor supply chain and enhance its

Revolutionized Low-Code

You Should Use Low-Code Platforms for Apps

As the demand for rapid software development increases, low-code platforms have emerged as a popular choice among developers for their ability to build applications with minimal coding. These platforms not

Cybersecurity Strategy

Five Powerful Strategies to Bolster Your Cybersecurity

In today’s increasingly digital landscape, businesses of all sizes must prioritize cyber security measures to defend against potential dangers. Cyber security professionals suggest five simple technological strategies to help companies

Global Layoffs

Tech Layoffs Are Getting Worse Globally

Since the start of 2023, the global technology sector has experienced a significant rise in layoffs, with over 236,000 workers being let go by 1,019 tech firms, as per data

Huawei Electric Dazzle

Huawei Dazzles with Electric Vehicles and Wireless Earbuds

During a prominent unveiling event, Huawei, the Chinese telecommunications powerhouse, kept quiet about its enigmatic new 5G phone and alleged cutting-edge chip development. Instead, Huawei astounded the audience by presenting

Cybersecurity Banking Revolution

Digital Banking Needs Cybersecurity

The banking, financial, and insurance (BFSI) sectors are pioneers in digital transformation, using web applications and application programming interfaces (APIs) to provide seamless services to customers around the world. Rising

FinTech Leadership

Terry Clune’s Fintech Empire

Over the past 30 years, Terry Clune has built a remarkable business empire, with CluneTech at the helm. The CEO and Founder has successfully created eight fintech firms, attracting renowned

The Role Of AI Within A Web Design Agency?

In the digital age, the role of Artificial Intelligence (AI) in web design is rapidly evolving, transitioning from a futuristic concept to practical tools used in design, coding, content writing

Generative AI Revolution

Is Generative AI the Next Internet?

The increasing demand for Generative AI models has led to a surge in its adoption across diverse sectors, with healthcare, automotive, and financial services being among the top beneficiaries. These

Microsoft Laptop

The New Surface Laptop Studio 2 Is Nuts

The Surface Laptop Studio 2 is a dynamic and robust all-in-one laptop designed for creators and professionals alike. It features a 14.4″ touchscreen and a cutting-edge design that is over

5G Innovations

GPU-Accelerated 5G in Japan

NTT DOCOMO, a global telecommunications giant, is set to break new ground in the industry as it prepares to launch a GPU-accelerated 5G network in Japan. This innovative approach will

AI Ethics

AI Journalism: Balancing Integrity and Innovation

An op-ed, produced using Microsoft’s Bing Chat AI software, recently appeared in the St. Louis Post-Dispatch, discussing the potential concerns surrounding the employment of artificial intelligence (AI) in journalism. These

Savings Extravaganza

Big Deal Days Extravaganza

The highly awaited Big Deal Days event for October 2023 is nearly here, scheduled for the 10th and 11th. Similar to the previous year, this autumn sale has already created

Cisco Splunk Deal

Cisco Splunk Deal Sparks Tech Acquisition Frenzy

Cisco’s recent massive purchase of Splunk, an AI-powered cybersecurity firm, for $28 billion signals a potential boost in tech deals after a year of subdued mergers and acquisitions in the

Iran Drone Expansion

Iran’s Jet-Propelled Drone Reshapes Power Balance

Iran has recently unveiled a jet-propelled variant of its Shahed series drone, marking a significant advancement in the nation’s drone technology. The new drone is poised to reshape the regional

Solar Geoengineering

Did the Overshoot Commission Shoot Down Geoengineering?

The Overshoot Commission has recently released a comprehensive report that discusses the controversial topic of Solar Geoengineering, also known as Solar Radiation Modification (SRM). The Commission’s primary objective is to