Structs areprogrammer-defined data types, very similar to classes. They have data members and function members. Althoughsimilar to classes, there are a number of important differences. The most important ones are the following:
Classes are reference types and structs are value types.
Structs are implicitly sealed, which means that they cannot be derived from.
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 variableof a struct type contains its own data. Consequently
For example, the following code declares a class called CSimple
, and 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(); ...
Assigning onestruct 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 the same as those of 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 } }
Structs can haveinstance 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 only supply an implicit parameterless constructor 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:
You cannot use the value of a data member until you have explicitly set it.
You cannot call any function member until all the data members have been assigned.
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:
A call to an explicitly declared constructor
A reference to a static member of the struct
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 bedeclared inthe program. Destructors are not allowed. |
Structs arealways implicitly sealed, and hence, you cannot derive other structs from them.
Since structs do notsupport 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, underthe 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 valuetype data, if you want to use a struct instance as a reference type object, you must make a boxed copy. Boxing and unboxing are covered in detail in Chapter 18.
Structs can be used as return values and parameters.
Return value: When a struct is a return value, a copy is created and returned from the function member.
Value parameter: When a struct is used as a value parameter, a copy of the actual parameter struct is created. The copy is used in the execution of the method.
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.
Allocatingstructs requires less overhead than creating instances of a class, so using structs instead of classes can sometimes improve performance—but beware of the high costof boxing and unboxing.
Finally, some last things you should know about structs are the following:
The predefined simple types (int, short, long
, etc.), although considered primitives in .NET and C#, are all actually implemented under the covers in .NET as structs.
You can declare 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.
3.145.8.8