Bits & Bytes

Posts Tagged ‘type’

Using C# Delegates to Call Static and Instance Functions

A delegate allows a programmer to abstract functions as variable values in the same way that he abstracts other data, such as integers and doubles, as variable values. Simply put, a delegate is a variable type that defines a specific type of function. An instance of the delegate can hold a reference to any function of that type.

Basic Steps for Using Delegates

  1. Declare a delegate type
  2. Create an instance of the type
  3. Assign that instance to a function
  4. Call the function via the delegate

The essential steps for using a delegate are listed above and demonstrated in the program below. The program consists of two files: Program.cs and CMyDelegateTester.cs–the additional class file is only needed for the second example.

For the first example, we can layout the steps very easily. First, we have the delegate declaration just above the Main() function, which designates our delegate type, DDoSomething. Next, we have the instantiation, pfnFunction, of the delegate type right after the first comment inside the Main() function. This instance is assigned to the static Square() function in the same line. Finally, we call the Square() function via the delegate in the next line with the value 3.0 and output the result.

In the second example, we do the same thing with an instance function of the CMyDelegateTester class. Notice that we need to instantiate the class and that we assign the function, along with its object, to the delegate. This is important because the delegate is attached to and will depend on the object in this case.

Executing the program, we see the output for each function call:

UsingDelegates

Program.cs

using System;

namespace UsingDelegates {
    class Program {

        delegate double DDoSomething(double dX);

        static void Main(string[] args) {

            // 1. An example using a static function
            DDoSomething pfnFunction = Square;
            Console.WriteLine("The static function returned " + pfnFunction(3.0));

            // 2. An example using a member function
            CMyDelegateTester qTesterObject = new CMyDelegateTester();
            DDoSomething mpfnMemberFunction = qTesterObject.MultiplyByTen;
            Console.WriteLine("The member function returned " + mpfnMemberFunction(3.0));
        }

        static double Square(double dX) {
            return dX * dX;
        }
    }
}

CMyDelegateTester.cs

namespace UsingDelegates {
    public class CMyDelegateTester {

        public CMyDelegateTester() {
        }

        public double MultiplyByTen(double dX) {
            return 10.0 * dX;
        }
    }
}

C# Delegates Versus C++ Function Pointers

A C# delegate is similar to a C++ function pointer. However, there are some subtle differences:

  1. C# delegates require the creation of a new data type. In fact, a delegate declaration is equivalent to a C++ typedef declaration of a function pointer type. While C++ does not require a new type definition to use function pointers, it is good practice.
  2. Like C++ function pointers, C# delegate types are detemined by the arguments and the return value. However, C++ distinguishes between static and instance functions and does not allow them to be used interchangeably as C# does. This is demonstrated in the C# code above.
  3. A C# delegate with a return type of void may be multicast to call multiple functions with one call. This is odd, but it is used with events and listeners, and will be illustrated in a future C# post.

Type Conversions of Primitive Types in Actionscript

We can perform explicit type conversions by using constructor notation like this:

var dFloat:Number = 3.14159;
var iConv:int = int(dFloat);

Here, we have the conversion of a floating-point (Number) type to an integer (int) type. A conversion from a Number to an int truncates the decimal so that the converted value “qConv” holds the value 3 after these lines are executed. In general, this is how the Number type gets converted to an int or a uint type: the value is simply truncated at the decimal point.

The Number type holds a much wider range than either the uint or int type can hold. When a Number type variable’s value lies outside the range of an int or a uint and a conversion takes place, a truncation occurs and the value is wrapped until it lies in the range of the target type.

var dFloat:Number = -3.14159;
var uiConv:uint = uint(dFloat);

In the example above, the negative value of “dFloat” lies outside the range of the uint type. So, the result of this conversion is 4294967293, which is the same value you would get if you converted an int with the value of -3 to the unsigned (uint) type.

var bBool:Boolean = true;
var uiConv:uint = uint(bBool);

We can convert numbers to booleans and vice versa. A Boolean variable with the value true gets converted to 1 and the value false gets converted to 0. This is the case regardless of whether the number type we are converting to is a uint, int or Number. So, the code segment above results in “uiConv” taking on the value 1 after the conversion.

var iNeg:int = -1;
var bConv:Boolean = Boolean(iNeg);

When converting to a Boolean type from a numerical type, the value 0 converts to false, as does the value NaN for Number type variables. All other numerical values convert to true. So, for example, the code above converts the value -1 to true.

Converting numerical types to a String is pretty straight-forward. The value is converted to a string representation of the number. Likewise, Boolean values are converted to the strings “true” or “false,” as expected.

var sString:String = "a3.14";
var dConv:Number = Number(sString);

However, converting values from a String type is somewhat strange. A String converts to a Boolean value of false if the String is null or empty (“”). Otherwise, it converts to true. A String converts to a number if it can be converted. If a String contains non-numeric characters it converts to 0 for int and uint types, but converts to NaN for a Number type. The code above converts the string “a3.14” to NaN.