Click here to Skip to main content
15,881,688 members
Articles / Programming Languages / C#
Article

Lagged Generics: Easily Constrain Change Rate of Variables

Rate me:
Please Sign up or sign in to vote.
4.44/5 (6 votes)
27 Dec 2007CPOL6 min read 19.3K   124   15  
This article shows a very basic example of using generics to create variables that cannot be changed faster than a specific rate
Screenshot - Article_source

Introduction

Generics are a huge improvement to the .NET and C# environment that came out with the 2.0 version of the platform. Basically, they allow to defer the specification of a type until the declaration and instantiation of a class or method in the client code. Later, you will find a deeper and easier explanation about them.

This article shows a very basic example of programming a generic class to perform a very specific functionality: constrain the change frequency of a variable, whatever its type is.

You will see that this functionality is very useful if you work with real-time applications where things go fast and not everything is event-driven, like games, simulators, or whatever.

About Generics

If you didn't understand a word about what they are (after all, this is a beginner's article), here goes an easier explanation.

There are some operations that must work with any kind of object. For example: a collection. Do we have to code a collection class to hold integers, a different one for floats, and a different one for our own customers? Of course we don't, that would be crazy!

So what can we do? Until .NET 1.1, the solution was to build a collection class that worked with objects. As everything in .NET inherits from the class object, everything can be put inside that kind of collection. This is still absolutely useful when we need collections that must hold different elements: an integer in the first place, a customer in the second, etc.

But the truth is that in many cases, we don't need different objects inside the same collection. So, if objects will all be the same, is that solution elegant? Not actually.

When we work with object as the base type, each time an element is accessed or inserted into the collection, it must be converted to and from object. This is known as boxing and unboxing, and implies a performance penalty, apart from additional code, work and some loss of comfort.

Since .NET 2.0, there's a better solution for this: generics.

Basically, and following with the collection example, they allow you to code your collection class working with an unspecified type, that by now will be called T. To specify your class as generic, your code must look like this:

C#
public class List<T> { ... } 

As you can see in the following example, this generic type T can be used all around your class as if it was a real type: like float, int, anything...

C#
public void Add(T pElement)
{
...
}

When your class is completed and any other part of your project or another person uses it, the type of the base object will have to be specified. For example, if you need a collection of customers, you can declare and instantiate it like this:

C#
MyCollections.List<MyCustomers> mList = new MyCollections.List<MyCustomers>();

This creates a list that can work only with objects of the type MyCustomer, and this is great because Visual Studio automatically recognizes it everywhere, and every parameter, every method, everything, will work with MyCustomer. This way, you strong-type your methods and classes, reducing mistakes and speeding up your coding, thanks to the intellisense.

As you can imagine, collections are the most obvious and direct use of generics and they come already implemented in .NET Framework 2.0 under the System.Collections.Generic namespace.

Anyway, a lot of different things can be done with generics, and this article shows one of them.

Where Will We Use Generics In This Example?

As we said before, when working in a real-time application like a game, not everything is event-driven. There are some parts of the code that must be executed as fast as the machine can, what usually leads programmers to work with a main loop, where the full logic of the application is parsed. Let me show you a little example of the problem.

Imagine an application of this kind. Not an event-driven one, but with a main loop where all the game logic is parsed. Imagine we have a flag somewhere that indicates if we want to render the options menu, for example. What activates and deactivates the options menu? Let's say, for example, a certain key-stroke.

Imagine now that for performance reasons, we are reading the keyboard through DirectX, which actually accesses directly to the keyboard hardware, bypassing the O.S. Now if the user hits that certain key, trying to switch the menu on or off, the application will in fact loop many times while the key is pressed, and will report that many times as well. If you don't avoid this somewhere else, the effect of that is that the menu will flicker a little bit, sometimes finally appearing, sometimes finally being hidden, all with a single key-stroke.

Obviously, something similar can happen in many situations, and it can be fixed in many different ways as well, maybe with simpler solutions. Anyway, I thought it would be fun to include some kind of timing to control the maximum change rate for a variable's value. To be honest, I've made no research about this issue, and probably it was already done somewhere else, but I guess it's a good example for beginners, so here we go!

Lagged Generics

As we said, our challenge is to control the maximum change rate for a variable. What kind of variable? Any, I guess... Ummmmhhh... This sounds familiar. Did I hear GENERICS somewhere?Yes, we have an operation that must work regardless of the type of the variable.

So, what you will find in the source code is the implementation of the class LaggedGeneric, which basically does that: it constrains the maximum rate at which the value of a variable can change.

First, we obviously need to declare the new class which probably will have some private members to control the maximum rate frequency. We will express this as the lag between changes, in seconds:

C#
public class LaggedGeneric<T><t />
{
      // Specify change frequency
      private double mLagSecs;
      private double mLastSetSeconds = 0;
      public double LagSecs
      {
          get { return mLagSecs; }
          set { mLagSecs = value; }
      }

      // Class´ constructor
      public LaggedGeneric(double pLagSecs)
      {
          this.mLagSecs = pLagSecs;
      }

We will also provide an event to report a value change. Just like this:

C#
// Events
public delegate void ValueChangedDelegate(
               LaggedGeneric<t /> pVar, T pNewValue, T pOldValue);
public event ValueChangedDelegate ValueChanged = null;

Now, we will have to store the value somewhere. Remember that we are working with generics. We do not know the type of data we will store, so we declare the variable mValue of the type T. We also provide a normal access property, to allow the user of this class to change the value directly (with no timing control or constraint). Every time the value changes, the ValueChanged event is fired.

C#
private T mValue;
// Normal access property. To change the value whenever you want
public T Value
{
   get { return mValue; }
   set
   {
      T old = mValue;
      mValue = value;
      if (!old.Equals(mValue) && ValueChanged != null)
          ValueChanged(this, mValue, old);
   }
}

Finally, we provide an additional access property with the name LaggedValue. This property will implement all the timing control.

C#
  // Lagged access property 
  public T LaggedValue
  {
      get { return this.mValue; }
      set
      {
          double difSecs = System.DateTime.Now.TimeOfDay.TotalSeconds - 
                           mLastSetSeconds;
          if (difSecs >= mLagSecs)
          {
              mLastSetSeconds = 
              System.DateTime.Now.TimeOfDay.TotalSeconds;
                   
              T old = mValue;
              mValue = value;

              if (!old.Equals(mValue) && ValueChanged != null)
                  ValueChanged(this, mValue, old);
          }
      }
  }
}  // end of class

Using the Code

In the source code attached with this article, you will find a full working Visual Studio 2005 Windows Forms project. It's very simple, and just shows a window that allows you to change the max change rate of a Lagged boolean flag. The application will try to change its value in every OnMouseMove event of the blue panel (which is fired every time the mouse cursor enters and moves around it). If you keep moving the mouse, you will see that the flag value changes exactly (more or less;) at the rate you specify in the NumericUpDown.

If you want to use the LaggedGeneric class in your project, just copy/paste the file into your solution and use it like in the following examples.

Declaration of a lagged boolean or flag (max change rate = 0.5 secs):

C#
LaggedGeneric<bool> mLaggedBoolean = new LaggedGeneric<bool>(0.5);

Value switching:

C#
mLaggedBollean.LaggedValue = !mLaggedBollean.LaggedValue;

This can, of course, be extended to any type of object you want to use. Hope you found it useful.

History

  • 26th December, 2007: First version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Spain Spain
Inaki Ayucar is a Microsoft MVP in DirectX/XNA, and a software engineer involved in development since his first Spectrum 48k, in the year 1987. He is the founder and chief developer of The Simax Project (www.simaxvirt.com) and is very interested in DirectX/XNA, physics, game development, simulation, C++ and C#.

His blog is: http://graphicdna.blogspot.com

To contact Inaki: iayucar@simax.es

Comments and Discussions

 
-- There are no messages in this forum --