Chapter 7. Structs

A struct is a simple user-defined type, a lightweight alternative to a class. Structs are similar to classes in that they may contain constructors, properties, methods, fields, operators, nested types, and indexers (see Chapter 9).

There are also significant differences between classes and structs. For instance, structs don’t support inheritance or destructors. More important, although a class is a reference type, a struct is a value type. (See Chapter 3 for more information about classes and types.) Thus, structs are useful for representing objects that don’t require reference semantics.

The consensus view is that you ought to use structs only for types that are small, simple, and similar in their behavior and characteristics to built-in types.

Tip

C++ programmers take note: the meaning of C#’s struct construct is very different from C++’s. In C++, a struct is exactly like a class, except that the visibility (public versus private) is different by default. In C#, structs are value types, whereas classes are reference types, and C# structs have other limitations, as described in this chapter.

Structs are somewhat more efficient in their use of memory in arrays (see Chapter 9). However, they can be less efficient when used in nongeneric collections. Collections that take objects expect references, and structs must be boxed. There is overhead in boxing and unboxing, and classes might be more efficient in some large collections. This concern is greatly ameliorated by using generic collections (see Chapter 9), and the truth is that many C# programmers go months at a time without using structs at all.

On the other hand, if you have a class that has, as its member variables, 10 structs instead of 10 objects, when that class is created on the heap, one big object is created (the class with its 10 structs) rather than 11 objects. That allows the garbage collector to do much less work when your containing class is ready to be destroyed, making your program more efficient. If you have a lot of classes like that, and you create and destroy them frequently, the performance differences can begin to be noticeable.

In this chapter, you will learn how to define and work with structs, and how to use constructors to initialize their values.

Defining Structs

The syntax for declaring a struct is almost identical to that for a class:

[attributes] [access-modifiers] struct identifier [:interface-list]
{ struct-members }

Example 7-1 illustrates the definition of a struct. Location represents a point on a two-dimensional surface. Notice that the struct Location is declared exactly as a class would be, except for the use of the keyword struct. Also notice that the Location constructor takes two integers and assigns their value to the instance members, xVal and yVal. The x and y coordinates of Location are declared as properties.

Example 7-1. Creating a struct
using System;


namespace CreatingAStruct
{
    public struct Location
    {
        public int X { get; set; }
        public int Y { get; set; }

        public override string ToString(  )
        {
            return (String.Format("{0}, {1}", X, Y));
        }

    }

    public class Tester
    {
        public void myFunc(Location loc)
        {
            loc.X = 50;
            loc.Y = 100;
            Console.WriteLine("In MyFunc loc: {0}", loc);
        }
        static void Main(  )
        {
            Location loc1 = new Location(  );
            loc1.X = 200;
            loc1.Y = 300;
            Console.WriteLine("Loc1 location: {0}", loc1);
            Tester t = new Tester(  );
            t.myFunc(loc1);
            Console.WriteLine("Loc1 location: {0}", loc1);
        }
    }
}

Output:
Loc1 location: 200, 300
In MyFunc loc: 50, 100
Loc1 location: 200, 300

Unlike classes, structs don’t support inheritance. They implicitly derive from Object (as do all types in C#, including the built-in types), but can’t inherit from any other class or struct. Structs are also implicitly sealed (i.e., no class or struct can derive from a struct). Like classes, however, structs can implement multiple interfaces. Additional differences include the following:

No destructor or custom default constructor

Structs can’t have destructors, nor can they have a custom parameterless (default) constructor; however, the CLR will initialize your structure and zero out all the fields if your object is called as though it had a default constructor, as shown in the example.

No initialization

You can’t initialize an instance field in a struct. Thus, it is illegal to write:

private int xVal = 50;
private int yVal = 100;

though that would have been fine had this been a class.

Structs are designed to be simple and lightweight. Although private member data promotes data-hiding and encapsulation, some programmers feel it is overkill for structs. They make the member data public, thus simplifying the implementation of the struct. Other programmers feel that properties provide a clean and simple interface, and that good programming practice demands data-hiding even with simple lightweight objects.

Creating Structs

You create an instance of a struct by using the new keyword in an assignment statement, just as you would for a class. In Example 7-1, the Tester class creates an instance of Location as follows:

Location loc1 = new Location(  );

Here, the new instance is named loc1, and the fields are initialized to 0. The example then uses the public properties to set the values of the fields to 200 and 300, respectively.

Structs As Value Types

The definition of the Tester class in Example 7-1 includes a Location object[8] struct (loc1) created with the values 200 and 300. This line of code calls the Location constructor:

Location loc1 = new Location(200,300);

Then WriteLine( ) is called:

Console.WriteLine("Loc1 location: {0}", loc1);

WriteLine( ) is expecting an object, but of course, Location is a struct (a value type). The compiler automatically wraps the struct in an object, a process called boxing (as it would any value type), and it is the boxed object that is passed to WriteLine( ). ToString( ) is called on the boxed object, and because the struct (implicitly) inherits from object, it is able to respond polymorphically, overriding the method just as any other object might:

Loc1 location: 200, 300

Tip

You can avoid this boxing by changing the preceding snippet to:

Console.WriteLine("Loc1 location: {0}",
    loc1.ToString(  ));

You avoid the box operation by calling ToString directly on a variable of a value type where the value type provides an override of ToString.

Structs are value objects, however, and when passed to a function, they are passed by value—as seen in the next line of code, in which the loc1 object is passed to the myFunc( ) method:

t.myFunc(loc1);

In myFunc( ), new values are assigned to x and y, and these new values are printed:

Loc1 location: 50, 100

When you return to the calling function (Main( )), and call WriteLine( ) again, the values are unchanged:

Loc1 location: 200, 300

The struct was passed as a value object, and a copy was made in myFunc( ). Try to change the declaration to class:

public class Location

and run the test again. Here is the output:

Loc1 location: 200, 300
In MyFunc loc: 50, 100
Loc1 location: 50, 100

This time the Location object has reference semantics. Thus, when the values are changed in myFunc( ), they are changed on the actual object back in Main( ).[9]



[8] * Throughout this book, I use the term object to refer to reference and value types. There is some debate in the object-oriented world about this, but I take solace in the fact that Microsoft has implemented the value types as though they inherited from the root class Object (and thus, you may call all of Object’s methods on any value type, including the built-in types such as int).

[9] * Another way to solve this problem is to use the keyword ref (as explained in the "Passing by Reference" section in Chapter 4), which allows you to pass a value type by reference.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.30.211