Field Initializers Are Not Allowed
Structs As Return Values and Parameters
Additional Information About Structs
Structs are programmer-defined data types, very similar to classes. They have data members and function members. Although similar to classes, there are a number of important differences. The most important ones are the following:
The syntax for declaring a struct is similar to that of declaring a class:
For example, the following code declares a struct named Point
. It has two public fields, named X
and Y
. In Main
, three variables of struct type Point
are declared, and their values are assigned and printed out.
struct Point
{
public int X;
public int Y;
}
class Program
{
static void Main()
{
Point first, second, third;
first.X = 10; first.Y = 10;
second.X = 20; second.Y = 20;
third.X = first.X + second.X;
third.Y = first.Y + second.Y;
Console.WriteLine("first: {0}, {1}", first.X, first.Y);
Console.WriteLine("second: {0}, {1}", second.X, second.Y);
Console.WriteLine("third: {0}, {1}", third.X, third.Y);
}
}
As with all value types, a variable of a struct type contains its own data. Consequently:
null
.For example, the following code declares a class called CSimple
, a struct called Simple
, and a variable of each. Figure 12-1 shows how the two would be arranged in memory.
class CSimple
{
public int X;
public int Y;
}
struct Simple
{
public int X;
public int Y;
}
class Program
{
static void Main()
{
CSimple cs = new CSimple();
Simple ss = new Simple();
...
Figure 12-1. Memory arrangement of a class versus a struct
Assigning one struct to another copies the values from one to the other. This is quite different from copying from a class variable, where only the reference is copied.
Figure 12-2 shows the difference between the assignment of a class variable and a struct variable. Notice that after the class assignment, cs2
is pointing at the same object in the heap as cs1
. But after the struct assignment, the values of ss2
's members are copies of those in ss1
.
class CSimple
{ public int X; public int Y; }
struct Simple
{ public int X; public int Y; }
class Program
{
static void Main()
{
CSimple cs1 = new CSimple(), cs2 = null; // Class instances
Simple ss1 = new Simple(), ss2 = new Simple(); // Struct instances
cs1.X = ss1.X = 5; // Assign 5 to ss1.X and cs1.X
cs1.Y = ss1.Y = 10; // Assign 10 to ss1.Y and cs1.Y
cs2 = cs1; // Assign class instance
ss2 = ss1; // Assign struct instance
}
}
Figure 12-2. Assigning a class variable and a struct variable
Structs can have instance and static constructors, but destructors are not allowed.
The language implicitly supplies a parameterless constructor for every struct. This constructor sets each of the struct's members to the default value for that type. Value members are set to their default values. Reference members are set to null
.
The predefined parameterless constructor exists for every struct—and you cannot delete or redefine it. You can, however, create additional constructors, as long as they have parameters. Notice that this is different from classes. For classes, the compiler will supply an implicit parameterless constructor only if no other constructors are declared.
To call a constructor, including the implicit parameterless constructor, use the new
operator. Notice that the new
operator is used even though the memory is not allocated from the heap.
For example, the following code declares a simple struct with a constructor that takes two int
parameters. Main
creates two instances of the struct—one using the implicit parameterless constructor and the second with the declared two-parameter constructor.
You can also create an instance of a struct without using the new
operator. If you do this, however, there are some restrictions, which are the following:
For example, the following code shows two instances of struct Simple
created without using the new
operator. When there is an attempt to access s1
without explicitly setting the data member values, the compiler produces an error message. There are no problems reading from s2
after assigning values to its members.
As with classes, the static constructors of structs create and initialize the static data members and cannot reference instance members. Static constructors for structs follow the same rules as those for classes.
A static constructor is called before the first of either of the following two actions:
Table 12-1 summarizes the use of constructors and destructors with structs.
Table 12-1. Summary of Constructors and Destructors
Type | Description |
Instance constructor (parameterless) | Cannot be declared in the program. An implicit constructor is supplied by the system for all structs. It cannot be deleted or redefined by the program. |
Instance constructor (with parameters) | Can be declared in the program. |
Static constructor | Can be declared in the program. |
Destructor | Cannot be declared in the program. Destructors are not allowed. |
Field initializers are not allowed in struct declarations, as shown in the following code:
Structs are always implicitly sealed, and hence you cannot derive other structs from them.
Since structs do not support inheritance, the use of several of the class member modifiers with struct members would not make sense; thus, they cannot be used in their declarations. The modifiers that cannot be used with structs are the following:
protected
internal
abstract
virtual
Structs themselves are, under the covers, derived from System.ValueType
, which is derived from object
.
The two inheritance-associated keywords you can use with struct members are the new
and override
modifiers, when creating a member with the same name as a member of base class System.ValueType
, from which all structs are derived.
As with other value type data, if you want to use a struct instance as a reference type object, you must make a boxed copy. Boxing and unboxing are explained in Chapter 18.
Structs can be used as return values and parameters.
ref
and out
parameters: If you use a struct as a ref
or out
parameter, a reference to the struct is passed into the method so that the data members can be changed.Allocating structs requires less overhead than creating instances of a class, so using structs instead of classes can sometimes improve performance—but beware of the high cost of boxing and unboxing.
Finally, some last things you should know about structs are the following:
int
, short
, long
, and so on), although considered primitives in .NET and C#, are all actually implemented under the covers in .NET as structs.partial
structs in the same way as partial
classes, as described in Chapter 6.Structs, like classes, can implement interfaces, which will be covered in Chapter 17.
18.191.139.169