Scope and Type of Variable and Performance in GDi+

This article has been excerpted from book "GraphicsProgramming with GDI+".

One of the best programming practices is the efficient use of variable and their scope. Before adding a new variable to a program, think for a second and ask yourself, "Do I really need this variable?" If you need a variable, do you really need it right now? The scope of variables and use of complex calculations can easily degrade the performance of your applications. Using global scope for pens, brushes, paths, and other objects may be useful instead of defining variable in the OnPaint or OnPaintBackGround methods.

Let's look at a practical example: Listing 13.5 is written on a form's paint event handler, which creates pens and brushes, and draws rectangles and polygons.

LISTING 13.5: Variables defined in the form's paint event handler

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Text;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace ScopeType
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {

            //Create brushed and pens
            HatchBrush hatchBrush = new HatchBrush(HatchStyle.HorizontalBrick, Color.Red, Color.Blue);
            Pen redPen = new Pen(Color.Red, 2);
            Pen hatchPen = new Pen(hatchBrush, 4);
            SolidBrush brush = new SolidBrush(Color.Green);
            //Create a points for curve
            Point p1 = new Point(40, 50);
            Point p2 = new Point(60, 70);
            Point p3 = new Point(80, 34);
            Point p4 = new Point(120, 180);
            Point p5 = new Point(200, 150);
            PointF[] ptsArray = { p1, p2, p3, p4, p5 };
            float width = this.ClientRectangle.Width - 100;
            float height = this.ClientRectangle.Height - 100;
            //float width = this.ClientRectangle.Width – 100;
            //float height = this.ClientRectangle.Height – 100;
 
            Point pt1 = new Point(40, 30);
            Point pt2 = new Point(80, 100);
            Color[] lnColors = { Color.Black, Color.Red };
            LinearGradientBrush lgBrush = new LinearGradientBrush(pt1, pt2, Color.Red, Color.Green);
            lgBrush.LinearColors = lnColors;
            lgBrush.GammaCorrection = true;
            //Draw objects
            e.Graphics.DrawPolygon(redPen, ptsArray);
          
            e.Graphics.DrawRectangle(hatchPen, x, y, width, height);
            e.Graphics.FillRectangle(lgBrush,
            200, 200, 200, 200);
            //Dispose of objects
            lgBrush.Dispose();
            brush.Dispose();
            hatchPen.Dispose();
            redPen.Dispose();
            hatchBrush.Dispose();
        }
    }
}

In this example we define many variables, all of local scope. Throughout the application, the redPen, hatchBrush, hatchPen, brush, and other variable remain the same. Programmatically, it doesn't matter whether we define these variables locally or globally; the choice depends entirely on the application. It may be better to have variables defined with a global scope. If you repaint the form frequently, defining these variables globally may improve performance because time will not be wasted on re-creating the objects for each pass. On the other hand, defining objects globally may consume more resources (memory).

It is also good to avoid lengthy calculations in frequently called routines. Here's an example: Listing 13.6 draws a line in a loop. As you can see, int x and int y are defined inside the loop.

LISTING 13.6: Defining variable inside a loop

            for (int i = 0; i < 10000; i++)
            {
                Pen bluePen = new Pen(Color.Blue);
                int x = 100;
                int y = 100;
                g.DrawLine(bluePen, 0, 0, x, y);
            }

We can easily replace the code in Listing 13.6 with Listing 13.7, which is more efficient. If a code statement does the same thing every time a control reaches it inside a loop, it is a good idea to move that statement outside the loop to save processing cycles.

LISTING 13.7: Defining variable outside a loop

            Pen bluePen = new Pen(Color.Blue);
            int x = 100;
            int y = 100;
            for (int i = 0; i < 10000; i++)
            {
                g.DrawLine(bluePen, 0, 0, x, y);
            }

Sometimes using a floating point data type instead of an integer may affect the quality of a drawing, even though floating point data is costly in terms of resources.

A well-designed and well-coded application also plays a vital role in performance. For example, replacing multiple if statements with a single case statement may improve performance.

Book.jpg