Using Structures as Records in C#

By John Paul Mueller, Bill Sempf, Chuck Sphar

The main reason to work with structures in most code is to create records that contain custom data. You use these custom data records to hold complex information and pass it around as needed within your application. It’s easier and faster to pass a single record than it is to pass a collection of data values, especially when your application performs the task regularly. Keep reading to find out how to use structures as a kind of data record.

Managing a single record

Passing structures to methods is cleaner and easier than passing a collection of individual data values. Of course, the values in the structure must be related in order for this strategy to work well. However, consider the following method:

static void DisplayMessage(Message msg)

{

Console.WriteLine(

"In response to Msg {0}, you can get {1} of {2} for {3}.",

msg.MsgID, msg.Qty, msg.ProductID, msg.Price);

}

In this case, the DisplayMessage() method receives a single input of type Message instead of the four variables that the method would normally require. Using the Message structure produces these positive results in the code:

  • The receiving method can assume that all the required data values are present.
  • The receiving method can assume that all the variables are initialized.
  • The caller is less likely to create erroneous code.
  • Other developers can read the code with greater ease.
  • Code changes are easier to make.

Adding structures to arrays

Applications rarely use a single data record for every purpose. In most cases, applications also include database-like collections of records. For example, an application is unlikely to receive just one Message. Instead, the application will likely receive a group of Message records, each of which it must process.

You can add structures to any collection. However, most collections work with objects, so adding a structure to them would incur a performance penalty because C# must box and unbox each structure individually. As the size of the collection increases, the penalty becomes quite noticeable. Consequently, it’s always a better idea to restrict collections of data records that rely on structures to arrays in your application when speed is the most important concern.

Working with an array of structures is much like working with an array of anything else. You could use code like this to create an array of Message structures:

// Display all the messages on screen.

Message[] Msgs = { myMsg, myMsg2 };

DisplayMessages(Msgs);

In this case, Msgs contains two records, myMsg and myMsg2. The code then processes the messages by passing the array to DisplayMessages(), which is shown here:

static void DisplayMessages(Message[] msgs)

{

foreach (Message item in msgs)

{

Console.WriteLine(

"In response to Msg {0}, you can get {1} of {2} for {3}.",

item.MsgID, item.Qty, item.ProductID, item.Price);

}

}

The DisplayMessages() method uses a foreach loop to separate the individual Message records. It then processes them using the same approach as DisplayMessage().

Overriding methods

Structures provide a great deal of flexibility that many developers assign exclusively to classes. For example, you can override methods, often in ways that make the structure output infinitely better. A good example is the ToString() method, which outputs a somewhat unhelpful (or something similar):

Structures.Program+Messages

The output isn’t useful because it doesn’t tell you anything. To garner anything useful, you must override the ToString() method by using code like this:

public override string ToString()

{

// Create a useful output string.

return "Message ID:\t" + MsgID +

"\r\nProduct ID:\t" + ProductID +

"\r\nQuantity:\t" + Qty +

"\r\nTotal Price:\t" + Price;

}

Now when you call ToString(), you obtain useful information. In this case, you see the following output when calling myMsg.ToString():

Message ID: 1

Product ID: 22

Quantity: 5

Total Price: 29.95