Section 7.2. Creating Structs


7.2. Creating Structs

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(200,300);

Here the new instance is named loc1 and is passed two values, 200 and 300.

7.2.1. Structs as Value Types

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

[1] Throughout this book, I use the term object to refer both to reference types and to 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 if 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).

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 boxes the struct (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

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 valueas 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 out:

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 changing 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().[2]

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

7.2.2. Creating Structs Without new

Because loc1 is a struct (not a class), it is created on the stack. Thus, in Example 7-1, when the new operator is called:

Location loc1 = new Location(200,300);

the resulting Location object is created on the stack.

The new operator calls the Location constructor. However, unlike with a class, it is possible to create a struct without using new at all. This is consistent with how built-in type variables (such as int) are defined, and is illustrated in Example 7-2.

A caveat: I am demonstrating how to create a struct without using new because it differentiates C# from C++ and also differentiates how C# treats classes versus structs. That said, however, creating structs without the keyword new brings little advantage and can create programs that are harder to understand, more error-prone, and more difficult to maintain. Proceed at your own risk.


Example 7-2. Creating a struct without using new
#region Using directives using System; using System.Collections.Generic; using System.Text; #endregion namespace StructWithoutNew {    public struct Location    {       public int xVal;       public int yVal;       public Location( int xCoordinate, int yCoordinate )       {          xVal = xCoordinate;          yVal = yCoordinate;       }       public int x       {          get          {             return xVal;          }          set          {             xVal = value;          }       }       public int y       {          get          {             return yVal;          }          set          {             yVal = value;          }       }       public override string ToString( )       {          return ( String.Format( "{0}, {1}", xVal, yVal ) );       }    }    public class Tester    {       static void Main( )       {          Location loc1;         // no call to the constructor          loc1.xVal = 75;        // initialize the members          loc1.yVal = 225;          Console.WriteLine( loc1 );       }    } }

In Example 7-2, you initialize the local variables directly, before calling a method of loc1 and before passing the object to WriteLine():

loc1.xVal = 75; loc1.yVal = 225;

If you were to comment out one of the assignments and recompile:

static void Main() {     Location loc1;     loc1.xVal = 75;  //   loc1.yVal = 225;     Console.WriteLine(loc1); }

you would get a compiler error:

Use of unassigned local variable 'loc1'

Once you assign all the values, you can access the values through the properties x and y:

static void Main() {     Location loc1;     loc1.xVal = 75;              // assign member variable     loc1.yVal = 225;             // assign member variable     loc1.x = 300;                // use property     loc1.y = 400;                // use property     Console.WriteLine(loc1); }

Be careful when using properties. Although they allow you to support encapsulation by making the actual values private, the properties themselves are actually member methods, and you can't call a member method until you initialize all the member variables.



Programming C#(c) Building. NET Applications with C#
Programming C#: Building .NET Applications with C#
ISBN: 0596006993
EAN: 2147483647
Year: 2003
Pages: 180
Authors: Jesse Liberty

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net