CATEGORII DOCUMENTE |
Structs are similar to classes in that they represent data structures that can contain data members and function members. Unlike classes, structs are value types and do not require heap allocation. A variable of a struct type directly contains the data of the struct, whereas a variable of a class type contains a reference to the data, the latter known as an object.
Structs are particularly useful for small data structures that have value semantics. Complex numbers, points in a coordinate system, or key-value pairs in a dictionary are all good examples of structs. Key to these data structures is that they have few data members, that they do not require use of inheritance or referential identity, and that they can be conveniently implemented using value semantics where assignment copies the value instead of the reference.
As described in 4.1.3, the simple types provided by C#, such as int, double, and bool, are in fact all struct types. Just as these predefined types are structs, so it is possible to use structs and operator overloading to implement new "primitive" types in the C# language. Two examples of such types are given in at the end of this chapter (11.4).
A struct-declaration is a type-declaration (9.5) that declares a new struct:
struct-declaration:
attributesopt
struct-modifiersopt struct identifier
struct-interfacesopt
struct-body ;opt
A struct-declaration consists of an optional set of attributes (17), followed by an optional set of struct-modifiers (11.1.1), followed by the keyword struct and an identifier that names the struct, followed by an optional struct-interfaces specification (11.1.2), followed by a struct-body (11.1.3), optionally followed by a semicolon.
A struct-declaration may optionally include a sequence of struct modifiers:
struct-modifiers:
struct-modifier
struct-modifiers struct-modifier
struct-modifier:
new
public
protected
internal
private
It is an error for the same modifier to appear multiple times in a struct declaration.
The modifiers of a struct declaration have the same meaning as those of a class declaration (10.1.1).
A struct declaration may include a struct-interfaces specification, in which case the struct is said to implement the given interface types.
struct-interfaces:
: interface-type-list
Interface implementations are discussed further in 13.4.
The struct-body of a struct defines the members of the struct.
struct-body:
The members of a struct consist of the members introduced by its struct-member-declarations and the members inherited from System.ValueType, which, in turn, inherits from object.
struct-member-declarations:
struct-member-declaration
struct-member-declarations
struct-member-declaration
struct-member-declaration:
constant-declaration
field-declaration
method-declaration
property-declaration
event-declaration
indexer-declaration
operator-declaration
constructor-declaration
static-constructor-declaration
type-declaration
Except for the differences noted in 11.3, the descriptions of class members provided in 10.2 through 10.11 apply to struct members as well.
Structs are value types (4.1) and are said to have value semantics. Classes, on the other hand, are reference types (4.2) and are said to have reference semantics.
A variable of a struct type directly contains the data of the struct, whereas a variable of a class type contains a reference to the data, the latter known as an object.
With classes, it is possible for two variables to reference the same object, and thus possible for operations on one variable to affect the object referenced by the other variable. With structs, the variables each have their own copy of the data, and it is not possible for operations on one to affect the other. Furthermore, because structs are not reference types, it is not possible for values of a struct type to be null.
Given the declaration
struct
Point
}
the code fragment
Point a
= new Point(10, 10);
Point b = a;
a.x = 100;
Console.WriteLine(b.x);
outputs the value 10. The assignment of a to b creates a copy of the value, and b is thus unaffected by the assignment to a.x. Had Point instead been declared as a class, the output would be 100 because a and b would reference the same object.
All struct types implicitly inherit from class object. A struct declaration may specify a list of implemented interfaces, but it is not possible for a struct declaration to specify a base class.
Struct types are never abstract and are always implicitly sealed. The abstract and sealed modifiers are therefore not permitted in a struct declaration.
Since inheritance isn't supported for structs, the declared accessibility of a struct member cannot be protected or protected internal.
Function members in a struct cannot be abstract or virtual, and the override modifier is allowed only to override methods inherited from the object type.
Assignment to a variable of a struct type creates a copy of the value being assigned. This differs from assignment to a variable of a class type, which copies the reference but not the object identified by the reference.
Similar to an assignment, when a struct is passed as a value parameter or returned as the result of a function member, a copy of the struct is created. A struct may be passed by reference to a function member using a ref or out parameter.
When a property or indexer of a struct is the target of an assignment, the instance expression associated with the property or indexer access must be classified as a variable. If the instance expression is classified as a value, a compile-time error occurs. This is described in further detail in 7.13.1.
As described in 5.2, several kinds of variables are automatically initialized to their default value when they are created. For variables of class types and other reference types, this default value is null. However, since structs are value types that cannot be null, the default value of a struct is the value produced by setting all value type fields to their default value and all reference type fields to null.
Referring to the Point struct declared above, the example
Point[] arr = new Point[100];
initializes each Point in the array to the value produced by setting the x and y fields to zero.
The default value of a struct corresponds to the value returned by the default constructor of the struct (4.1.1). Unlike a class, a struct is not permitted to declare a parameterless instance constructor. Instead, every struct implicitly has a parameterless instance constructor which always returns the value that results from "zeroing out" the fields of the struct.
Structs should be designed to consider the default initialization state a valid state. In the example
struct
KeyValuePair
}
the user-defined instance constructor protects against null values only where it is explicitly called. In cases where a KeyValuePair variable is subject to default value initialization, the key and value fields will be null, and the struct must be prepared to handle this state.
A value of a class type can be converted to type object or to an interface type that is implemented by the class simply by treating the reference as another type at compile-time. Likewise, a value of type object or a value of an interface type can be converted back to a class type without changing the reference (but of course a run-time type check is required in this case).
Since structs are not reference types, these operations are implemented differently for struct types. When a value of a struct type is converted to type object or to an interface type that is implemented by the struct, a boxing operation takes place. Likewise, when a value of type object or a value of an interface type is converted back to a struct type, an unboxing operation takes place. A key difference from the same operations on class types is that boxing and unboxing copies the struct value either into or out of the boxed instance. Thus, following a boxing or unboxing operation, changes made to the unboxed struct are not reflected in the boxed struct.
For further details on boxing and unboxing, see 4.3.
Within an instance constructor or instance function member of a class, this is classified as a value. Thus, while this can be used to refer to the instance for which the function member was invoked, it is not possible to assign to this in a function member of a class.
Within an instance constructor of a struct, this corresponds to an out parameter of the struct type, and within an instance function member of a struct, this corresponds to a ref parameter of the struct type. In both cases, this is classified as a variable, and it is possible to modify the entire struct for which the function member was invoked by assigning to this or by passing this as a ref or out parameter.
As described in 11.3.4, the default value of a struct consists of the value that results from setting all value type fields to their default value and all reference type fields to null.. For this reason, a struct does not permit instance field declarations to include variable initializers, and the following example is invalid:
struct
Point
This restriction applies only to instance fields. Static fields of a struct are permitted to include variable initializers.
Unlike a class, a struct is not permitted to declare a parameterless instance constructor. Instead, every struct implicitly has a parameterless instance constructor which always returns the value that results from setting all value type fields to their default value and all reference type fields to null (4.1.1).
A struct instance constructor is not permitted to include a constructor initializer of the form base().
The this variable of a struct instance constructor corresponds to an out parameter of the struct type, and similar to an out parameter, this must be definitely assigned (5.3) at every location where the instance constructor returns.
A struct can declare instance constructors having parameters. In the example
struct
Point
}
the struct Point declares a instance constructor with two int parameters. Given this declaration, the statements
Point p1 = new Point();
Point p2 = new Point(0, 0);
both create a Point with x and y initialized to zero.
A struct is not permitted to declare a destructor.
The DBInt struct below implements an integer type that can represent the complete set of values of the int type, plus an additional state that indicates an unknown value. A type with these characteristics is commonly used in databases.
public
struct DBInt
// The IsNull property is true if this DBInt represents an unknown value.
public bool IsNull }
// The Value property is the known value of
this DBInt, or 0 if this
// DBInt represents an unknown value.
public int Value }
// Implicit conversion from int to DBInt.
public static implicit operator DBInt(int x)
// Explicit conversion from DBInt to int.
Throws an exception if the
// given DBInt represents an unknown
value.
public static explicit operator int(DBInt x)
public static DBInt operator +(DBInt x)
public static DBInt operator -(DBInt x)
public static DBInt operator +(DBInt x, DBInt y)
public static DBInt operator -(DBInt x, DBInt y)
public static DBInt operator *(DBInt x, DBInt y)
public static DBInt operator /(DBInt x, DBInt y)
public static DBInt operator %(DBInt x, DBInt y)
public static DBBool operator ==(DBInt x, DBInt y)
public static DBBool operator !=(DBInt x, DBInt y)
public static DBBool operator >(DBInt x, DBInt y)
public static DBBool operator <(DBInt x, DBInt y)
public static DBBool operator >=(DBInt x, DBInt y)
public static DBBool operator <=(DBInt x, DBInt y)
public override bool Equals(object o)
catch
}
public override int GetHashCode()
public override string ToString() }
The DBBool struct below implements a three-valued logical type. The possible values of this type are DBBool.True, DBBool.False, and DBBool.Null, where the Null member indicates an unknown value. Such three-valued logical types are commonly used in databases.
public
struct DBBool
// Properties to examine the value of a
DBBool. Return true if this
// DBBool has the given value, false
otherwise.
public bool IsNull }
public bool IsFalse }
public bool IsTrue }
// Implicit conversion from bool to DBBool.
Maps true to DBBool.True and
// false to DBBool.False.
public static implicit operator DBBool(bool x)
// Explicit conversion from DBBool to bool.
Throws an exception if the
// given DBBool is Null, otherwise
returns true or false.
public static explicit operator bool(DBBool x)
// Equality operator. Returns Null if
either operand is Null, otherwise
// returns True or False.
public static DBBool operator ==(DBBool x, DBBool y)
// Inequality operator. Returns Null if
either operand is Null, otherwise
// returns True or False.
public static DBBool operator !=(DBBool x, DBBool y)
// Logical negation operator. Returns True
if the operand is False, Null
// if the operand is Null, or False
if the operand is True.
public static DBBool operator !(DBBool x)
// Logical AND operator. Returns False if
either operand is False,
// otherwise Null if either operand
is Null, otherwise True.
public static DBBool operator &(DBBool x, DBBool y)
// Logical OR operator. Returns True if
either operand is True, otherwise
// Null if either operand is Null,
otherwise False.
public static DBBool operator |(DBBool x, DBBool y)
// Definitely true operator. Returns true
if the operand is True, false
// otherwise.
public static bool operator true(DBBool x)
// Definitely false operator. Returns true
if the operand is False, false
// otherwise.
public static bool operator false(DBBool x)
public override bool Equals(object o)
catch
}
public override int GetHashCode()
public override string ToString()
}}
Politica de confidentialitate | Termeni si conditii de utilizare |
Vizualizari: 960
Importanta:
Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved