结构Structs
结构与类相似,它们表示可以包含数据成员和函数成员的数据结构。Structs are similar to classes in that they represent data structures that can contain data members and function members. 但是,与类不同的是,结构是值类型,不需要进行堆分配。However, 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.
如 简单类型中所述,c # 提供的简单类型(如 int
、 double
和 bool
)实际上都是所有结构类型。As described in Simple types, the simple types provided by C#, such as int
, double
, and bool
, are in fact all struct types. 正如这些预定义类型是结构一样,还可以使用结构和运算符重载来实现 c # 语言的新 "基元" 类型。Just as these predefined types are structs, it is also possible to use structs and operator overloading to implement new "primitive" types in the C# language. 本章末尾提供了此类类型的两个示例 (结构示例) 。Two examples of such types are given at the end of this chapter (Struct examples).
结构声明Struct declarations
Struct_declaration 是声明新结构 (类型声明) type_declaration :A struct_declaration is a type_declaration (Type declarations) that declares a new struct:
struct_declaration
: attributes? struct_modifier* 'partial'? 'struct' identifier type_parameter_list?
struct_interfaces? type_parameter_constraints_clause* struct_body ';'?
;
Struct_declaration 包含一组可选的 特性 (特性) ,后跟一组可选的 struct_modifier s (结构修饰符) ,后跟一个可选 partial
修饰符,后面跟一个关键字 struct
和一个命名该结构的 标识符,后跟一个可选的 type_parameter_list 规范 (类型参数") ,后跟一个可选的 struct_interfaces 规范 (Partial 修饰符) ,后跟一个可选的 ) type_parameter_constraints_clause 类型参数约束 (,后跟一个可选的 )结构体struct_body,后面可以跟一个分号。A struct_declaration consists of an optional set of attributes (Attributes), followed by an optional set of struct_modifier s (Struct modifiers), followed by an optional partial
modifier, followed by the keyword struct
and an identifier that names the struct, followed by an optional type_parameter_list specification (Type parameters), followed by an optional struct_interfaces specification (Partial modifier) ), followed by an optional type_parameter_constraints_clause s specification (Type parameter constraints), followed by a struct_body (Struct body), optionally followed by a semicolon.
结构修饰符Struct modifiers
Struct_declaration 可以选择性地包含一系列结构修饰符:A struct_declaration may optionally include a sequence of struct modifiers:
struct_modifier
: 'new'
| 'public'
| 'protected'
| 'internal'
| 'private'
| struct_modifier_unsafe
;
同一修饰符在结构声明中出现多次是编译时错误。It is a compile-time 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 (Class declarations).
Partial 修饰符Partial modifier
partial
修饰符指示此 struct_declaration 是分部类型声明。The partial
modifier indicates that this struct_declaration is a partial type declaration. 在封闭命名空间或类型声明中具有相同名称的多个分部结构声明组合在一起,并遵循在 部分类型中指定的规则组成一个结构声明。Multiple partial struct declarations with the same name within an enclosing namespace or type declaration combine to form one struct declaration, following the rules specified in Partial types.
结构接口Struct interfaces
结构声明可以包含 struct_interfaces 规范,在这种情况下,结构被称为直接实现给定的接口类型。A struct declaration may include a struct_interfaces specification, in which case the struct is said to directly implement the given interface types.
struct_interfaces
: ':' interface_type_list
;
接口实现中进一步讨论了接口实现。Interface implementations are discussed further in Interface implementations.
结构体Struct body
结构的 struct_body 定义结构的成员。The struct_body of a struct defines the members of the struct.
struct_body
: '{' struct_member_declaration* '}'
;
结构成员Struct members
结构的成员由其 struct_member_declaration 引入的成员和从该类型继承的成员组成 System.ValueType
。The members of a struct consist of the members introduced by its struct_member_declaration s and the members inherited from the type System.ValueType
.
struct_member_declaration
: constant_declaration
| field_declaration
| method_declaration
| property_declaration
| event_declaration
| indexer_declaration
| operator_declaration
| constructor_declaration
| static_constructor_declaration
| type_declaration
| struct_member_declaration_unsafe
;
除了类和结构差异中所述的区别外,通过异步函数在类成员中提供的类成员的说明也适用于结构成员。Except for the differences noted in Class and struct differences, the descriptions of class members provided in Class members through Async functions apply to struct members as well.
类和结构的区别Class and struct differences
结构在几个重要方面不同于类:Structs differ from classes in several important ways:
- 结构是值类型 () 的值 语义 。Structs are value types (Value semantics).
- 所有结构类型都隐式继承自类,
System.ValueType
(继承) 。All struct types implicitly inherit from the classSystem.ValueType
(Inheritance). - 对结构类型的变量赋值会创建 (赋值) 分配的值的副本。Assignment to a variable of a struct type creates a copy of the value being assigned (Assignment).
- 结构的默认值是通过将所有值类型字段设置为其默认值,并将所有引用类型字段设置为
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 tonull
(Default values). - 装箱和取消装箱操作用于在结构类型和
object
(装箱和取消装箱) 之间进行转换。Boxing and unboxing operations are used to convert between a struct type andobject
(Boxing and unboxing). this
此访问) (结构的含义不同。The meaning ofthis
is different for structs (This access).- 结构的实例字段声明不允许包含变量初始值设定项 (字段初始值设定 项) 。Instance field declarations for a struct are not permitted to include variable initializers (Field initializers).
- 不允许结构) (构造函数 声明无参数的实例构造函数。A struct is not permitted to declare a parameterless instance constructor (Constructors).
- 不允许结构将析构函数声明 (析构函数) 。A struct is not permitted to declare a destructor (Destructors).
值语义Value semantics
结构是值 类型 (值类型) 并且称为具有值语义。Structs are value types (Value types) and are said to have value semantics. 另一方面,类是引用类型 (引用 类型) 并被认为具有引用语义。Classes, on the other hand, are reference types (Reference types) 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. 如果结构 B
包含类型为的实例字段 A
并且 A
是结构类型,则它是依赖于 A
B
或从构造的类型的编译时错误 B
。When a struct B
contains an instance field of type A
and A
is a struct type, it is a compile-time error for A
to depend on B
or a type constructed from B
. X
* Y
如果 X
包含类型的实例字段,则结构直接依赖于 _ a 结构 Y
。A struct X
*directly depends on _ a struct Y
if X
contains an instance field of type Y
. 根据此定义,结构所依赖的完整结构集是 _ 直接依赖于* 关系的传递闭包。Given this definition, the complete set of structs upon which a struct depends is the transitive closure of the _ directly depends on* relationship. 例如For example
struct Node
{
int data;
Node next; // error, Node directly depends on itself
}
是一个错误,因为 Node
包含自己的类型的实例字段。is an error because Node
contains an instance field of its own type. 另一个示例Another example
struct A { B b; }
struct B { C c; }
struct C { A a; }
是一个错误,因为每个类型 A
、 B
和相互 C
依赖。is an error because each of the types A
, B
, and C
depend on each other.
对于类,两个变量可以引用同一对象,因此,对一个变量执行的运算可能会影响另一个变量所引用的对象。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. 使用结构,每个变量都有自己的数据副本 (除了 ref
和 out
参数变量) 以外,对一个变量执行的操作不可能影响另一个变量。With structs, the variables each have their own copy of the data (except in the case of ref
and out
parameter variables), and it is not possible for operations on one to affect the other. 此外,由于结构不是引用类型,因此结构类型的值不能为 null
。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
{
public int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
代码片段the code fragment
Point a = new Point(10, 10);
Point b = a;
a.x = 100;
System.Console.WriteLine(b.x);
输出值 10
。outputs the value 10
. 的赋值 a
b
创建值的副本, b
因此不受赋值的影响 a.x
。The assignment of a
to b
creates a copy of the value, and b
is thus unaffected by the assignment to a.x
. Point
改为将其声明为类, 100
因为 a
和 b
将引用相同的对象。Had Point
instead been declared as a class, the output would be 100
because a
and b
would reference the same object.
继承Inheritance
所有结构类型都隐式继承自类 System.ValueType
,后者又继承自类 object
。All struct types implicitly inherit from the class System.ValueType
, which, in turn, inherits 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. abstract
因此, sealed
在结构声明中不允许使用和修饰符。The abstract
and sealed
modifiers are therefore not permitted in a struct declaration.
由于结构不支持继承,因此结构成员的声明的可访问性不能是 protected
或 protected internal
。Since inheritance isn't supported for structs, the declared accessibility of a struct member cannot be protected
or protected internal
.
结构中的函数成员不能是 abstract
或 virtual
,且 override
修饰符只允许重写从继承的方法 System.ValueType
。Function members in a struct cannot be abstract
or virtual
, and the override
modifier is allowed only to override methods inherited from System.ValueType
.
分配Assignment
对结构类型的变量赋值会创建要分配的值的副本。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. 可以通过使用或参数对函数成员的引用来传递结构 ref
out
。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 Simple assignment.
默认值Default values
如 " 默认值" 中所述,在创建多个变量时,它们会自动初始化为其默认值。As described in Default values, several kinds of variables are automatically initialized to their default value when they are created. 对于类类型和其他引用类型的变量,此默认值为 null
。For variables of class types and other reference types, this default value is null
. 但是,由于结构是值类型,因此, null
结构的默认值是通过将所有值类型字段设置为其默认值和所有引用类型字段而产生的值 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
.
引用 Point
上面声明的结构,示例Referring to the Point
struct declared above, the example
Point[] a = new Point[100];
将数组中的每个初始化 Point
为通过将 x
和字段设置为零而产生的值 y
。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 (Default constructors). 与类不同,结构不允许声明无参数的实例构造函数。Unlike a class, a struct is not permitted to declare a parameterless instance constructor. 相反,每个结构都隐式包含一个无参数的实例构造函数,该构造函数始终返回通过将所有值类型字段设置为其默认值和所有引用类型字段而产生的值 null
。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
.
结构应设计为将默认初始化状态视为有效状态。Structs should be designed to consider the default initialization state a valid state. 示例中In the example
using System;
struct KeyValuePair
{
string key;
string value;
public KeyValuePair(string key, string value) {
if (key == null || value == null) throw new ArgumentException();
this.key = key;
this.value = value;
}
}
用户定义实例构造函数仅在显式调用它的位置保护 null 值。the user-defined instance constructor protects against null values only where it is explicitly called. 如果 KeyValuePair
变量服从默认值初始化,则 key
和 value
字段将为 null,并且该结构必须准备好处理此状态。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.
装箱和取消装箱Boxing and unboxing
类类型的值可以转换为类型 object
或由类实现的接口类型,只需在编译时将引用视为另一种类型。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. 同样,可以将类型的值 object
或接口类型的值转换回类类型,而无需更改引用 (但在这种情况下,需要运行时类型检查) 。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. 当结构类型的值转换为类型 object
或结构实现的接口类型时,将发生装箱操作。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. 同样,如果类型的值 object
或接口类型的值转换回结构类型,则会发生取消装箱操作。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.
当结构类型重写从 System.Object
((如、或) )继承的虚方法时 Equals
GetHashCode
ToString
,通过该结构类型的实例调用虚拟方法不会导致装箱发生。When a struct type overrides a virtual method inherited from System.Object
(such as Equals
, GetHashCode
, or ToString
), invocation of the virtual method through an instance of the struct type does not cause boxing to occur. 即使将结构用作类型参数,并且通过类型参数类型的实例进行调用,也是如此。This is true even when the struct is used as a type parameter and the invocation occurs through an instance of the type parameter type. 例如:For example:
using System;
struct Counter
{
int value;
public override string ToString() {
value++;
return value.ToString();
}
}
class Program
{
static void Test<T>() where T: new() {
T x = new T();
Console.WriteLine(x.ToString());
Console.WriteLine(x.ToString());
Console.WriteLine(x.ToString());
}
static void Main() {
Test<Counter>();
}
}
该程序的输出为:The output of the program is:
1
2
3
尽管对具有副作用的样式是不正确的 ToString
,但该示例演示了对的三个调用没有发生装箱 x.ToString()
。Although it is bad style for ToString
to have side effects, the example demonstrates that no boxing occurred for the three invocations of x.ToString()
.
同样,在访问受约束的类型参数上的成员时,不会隐式进行装箱。Similarly, boxing never implicitly occurs when accessing a member on a constrained type parameter. 例如,假设某个接口 ICounter
包含一个 Increment
可用于修改值的方法。For example, suppose an interface ICounter
contains a method Increment
which can be used to modify a value. 如果 ICounter
用作约束,则会 Increment
调用方法的实现,该方法具有对调用的变量的引用 Increment
,而不是装箱副本。If ICounter
is used as a constraint, the implementation of the Increment
method is called with a reference to the variable that Increment
was called on, never a boxed copy.
using System;
interface ICounter
{
void Increment();
}
struct Counter: ICounter
{
int value;
public override string ToString() {
return value.ToString();
}
void ICounter.Increment() {
value++;
}
}
class Program
{
static void Test<T>() where T: ICounter, new() {
T x = new T();
Console.WriteLine(x);
x.Increment(); // Modify x
Console.WriteLine(x);
((ICounter)x).Increment(); // Modify boxed copy of x
Console.WriteLine(x);
}
static void Main() {
Test<Counter>();
}
}
用于 Increment
修改变量中的值的第一次调用 x
。The first call to Increment
modifies the value in the variable x
. 这与对的第二次调用不等效 Increment
,后者修改的装箱副本中的值 x
。This is not equivalent to the second call to Increment
, which modifies the value in a boxed copy of x
. 因此,该程序的输出为:Thus, the output of the program is:
0
1
1
有关装箱和取消装箱的更多详细信息,请参阅 装箱和取消装箱。For further details on boxing and unboxing, see Boxing and unboxing.
含义Meaning of this
在类的实例构造函数或实例函数成员内, this
分类为值。Within an instance constructor or instance function member of a class, this
is classified as a value. 因此,虽然 this
可用于引用调用了函数成员的实例,但不能 this
在类的函数成员中对赋值。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.
在结构的实例构造函数中, this
对应于结构 out
类型的参数,并在结构的实例函数成员内与 this
ref
结构类型的参数对应。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. 在这两种情况下, this
都归类为变量,并且可以通过将 this
此函数作为或参数传递来修改调用了函数成员的整个结构 ref
out
。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.
字段初始值设定项Field initializers
如 " 默认值" 中所述,结构的默认值由将所有值类型字段设置为其默认值并将所有引用类型字段设置为而产生的值 null
。As described in Default values, 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. 此限制仅适用于实例字段。This restriction applies only to instance fields. 允许结构的静态字段包含变量初始值设定项。Static fields of a struct are permitted to include variable initializers.
示例The example
struct Point
{
public int x = 1; // Error, initializer not permitted
public int y = 1; // Error, initializer not permitted
}
出现错误,因为实例字段声明包含变量初始值设定项。is in error because the instance field declarations include variable initializers.
构造函数Constructors
与类不同,结构不允许声明无参数的实例构造函数。Unlike a class, a struct is not permitted to declare a parameterless instance constructor. 相反,每个结构都隐式包含一个无参数的实例构造函数,该构造函数始终返回将所有值类型字段设置为其默认值并将所有引用类型字段设置为 null (默认构造函数) 时得出的值。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 (Default constructors). 结构可声明具有参数的实例构造函数。A struct can declare instance constructors having parameters. 例如For example
struct Point
{
int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
给定上述声明,语句Given the above declaration, the statements
Point p1 = new Point();
Point p2 = new Point(0, 0);
两者均使用创建一个 Point
x
,并 y
将其初始化为零。both create a Point
with x
and y
initialized to zero.
不允许结构实例构造函数包含形式的构造函数初始值设定项 base(...)
。A struct instance constructor is not permitted to include a constructor initializer of the form base(...)
.
如果结构实例构造函数未指定构造函数初始值设定项,则 this
变量与 out
结构类型的参数对应,与 out
参数类似,必须在 this
构造函数返回的每个位置 (明确赋值) 明确赋值。If the struct instance constructor doesn't specify a constructor initializer, the this
variable corresponds to an out
parameter of the struct type, and similar to an out
parameter, this
must be definitely assigned (Definite assignment) at every location where the constructor returns. 如果结构实例构造函数指定构造函数初始值设定项,则 this
变量与结构类型的参数相对应,与 ref
参数类似 ref
, this
在进入构造函数主体时被视为已明确赋值。If the struct instance constructor specifies a constructor initializer, the this
variable corresponds to a ref
parameter of the struct type, and similar to a ref
parameter, this
is considered definitely assigned on entry to the constructor body. 请考虑下面的实例构造函数实现:Consider the instance constructor implementation below:
struct Point
{
int x, y;
public int X {
set { x = value; }
}
public int Y {
set { y = value; }
}
public Point(int x, int y) {
X = x; // error, this is not yet definitely assigned
Y = y; // error, this is not yet definitely assigned
}
}
不 (包括属性和) 的 set 访问器的实例成员函数 X
, Y
直到构造的结构的所有字段都已明确赋值。No instance member function (including the set accessors for the properties X
and Y
) can be called until all fields of the struct being constructed have been definitely assigned. 唯一的例外涉及自动实现属性, (自动实现) 的属性。The only exception involves automatically implemented properties (Automatically implemented properties). 明确的赋值规则 (简单赋值表达式 ,) 在该结构类型的实例构造函数中明确分配对结构类型的自动属性的赋值:此类赋值被视为自动属性的隐藏支持字段的明确分配。The definite assignment rules (Simple assignment expressions) specifically exempt assignment to an auto-property of a struct type within an instance constructor of that struct type: such an assignment is considered a definite assignment of the hidden backing field of the auto-property. 因此,可以使用以下内容:Thus, the following is allowed:
struct Point
{
public int X { get; set; }
public int Y { get; set; }
public Point(int x, int y) {
X = x; // allowed, definitely assigns backing field
Y = y; // allowed, definitely assigns backing field
}
析构函数Destructors
不允许结构声明析构函数。A struct is not permitted to declare a destructor.
静态构造函数Static constructors
结构的静态构造函数遵循与类相同的大多数规则。Static constructors for structs follow most of the same rules as for classes. 在应用程序域中发生以下事件的第一个事件时,将触发结构类型的静态构造函数的执行:The execution of a static constructor for a struct type is triggered by the first of the following events to occur within an application domain:
- 引用结构类型的静态成员。A static member of the struct type is referenced.
- 将调用结构类型的显式声明的构造函数。An explicitly declared constructor of the struct type is called.
(默认值) 结构类型的 默认 值的创建不会触发静态构造函数。The creation of default values (Default values) of struct types does not trigger the static constructor. (的一个示例是数组中元素的初始值。 ) (An example of this is the initial value of elements in an array.)
结构示例Struct examples
下面显示了两个使用 struct
类型创建类型的示例,这些类型可以与语言的预定义类型相似,但使用修改后的语义。The following shows two significant examples of using struct
types to create types that can be used similarly to the predefined types of the language, but with modified semantics.
数据库整数类型Database integer type
DBInt
下面的结构实现整数类型,该类型可以表示类型的完整值集 int
,另外还实现了指示未知值的附加状态。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.
using System;
public struct DBInt
{
// The Null member represents an unknown DBInt value.
public static readonly DBInt Null = new DBInt();
// When the defined field is true, this DBInt represents a known value
// which is stored in the value field. When the defined field is false,
// this DBInt represents an unknown value, and the value field is 0.
int value;
bool defined;
// Private instance constructor. Creates a DBInt with a known value.
DBInt(int value) {
this.value = value;
this.defined = true;
}
// The IsNull property is true if this DBInt represents an unknown value.
public bool IsNull { get { return !defined; } }
// The Value property is the known value of this DBInt, or 0 if this
// DBInt represents an unknown value.
public int Value { get { return value; } }
// Implicit conversion from int to DBInt.
public static implicit operator DBInt(int x) {
return new DBInt(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) {
if (!x.defined) throw new InvalidOperationException();
return x.value;
}
public static DBInt operator +(DBInt x) {
return x;
}
public static DBInt operator -(DBInt x) {
return x.defined ? -x.value : Null;
}
public static DBInt operator +(DBInt x, DBInt y) {
return x.defined && y.defined? x.value + y.value: Null;
}
public static DBInt operator -(DBInt x, DBInt y) {
return x.defined && y.defined? x.value - y.value: Null;
}
public static DBInt operator *(DBInt x, DBInt y) {
return x.defined && y.defined? x.value * y.value: Null;
}
public static DBInt operator /(DBInt x, DBInt y) {
return x.defined && y.defined? x.value / y.value: Null;
}
public static DBInt operator %(DBInt x, DBInt y) {
return x.defined && y.defined? x.value % y.value: Null;
}
public static DBBool operator ==(DBInt x, DBInt y) {
return x.defined && y.defined? x.value == y.value: DBBool.Null;
}
public static DBBool operator !=(DBInt x, DBInt y) {
return x.defined && y.defined? x.value != y.value: DBBool.Null;
}
public static DBBool operator >(DBInt x, DBInt y) {
return x.defined && y.defined? x.value > y.value: DBBool.Null;
}
public static DBBool operator <(DBInt x, DBInt y) {
return x.defined && y.defined? x.value < y.value: DBBool.Null;
}
public static DBBool operator >=(DBInt x, DBInt y) {
return x.defined && y.defined? x.value >= y.value: DBBool.Null;
}
public static DBBool operator <=(DBInt x, DBInt y) {
return x.defined && y.defined? x.value <= y.value: DBBool.Null;
}
public override bool Equals(object obj) {
if (!(obj is DBInt)) return false;
DBInt x = (DBInt)obj;
return value == x.value && defined == x.defined;
}
public override int GetHashCode() {
return value;
}
public override string ToString() {
return defined? value.ToString(): "DBInt.Null";
}
}
数据库布尔类型Database boolean type
DBBool
下面的结构实现了三值逻辑类型。The DBBool
struct below implements a three-valued logical type. 此类型的可能值为 DBBool.True
、 DBBool.False
和 DBBool.Null
,其中 Null
成员指示未知值。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.
using System;
public struct DBBool
{
// The three possible DBBool values.
public static readonly DBBool Null = new DBBool(0);
public static readonly DBBool False = new DBBool(-1);
public static readonly DBBool True = new DBBool(1);
// Private field that stores -1, 0, 1 for False, Null, True.
sbyte value;
// Private instance constructor. The value parameter must be -1, 0, or 1.
DBBool(int value) {
this.value = (sbyte)value;
}
// Properties to examine the value of a DBBool. Return true if this
// DBBool has the given value, false otherwise.
public bool IsNull { get { return value == 0; } }
public bool IsFalse { get { return value < 0; } }
public bool IsTrue { get { return value > 0; } }
// Implicit conversion from bool to DBBool. Maps true to DBBool.True and
// false to DBBool.False.
public static implicit operator DBBool(bool x) {
return x? True: False;
}
// 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) {
if (x.value == 0) throw new InvalidOperationException();
return x.value > 0;
}
// Equality operator. Returns Null if either operand is Null, otherwise
// returns True or False.
public static DBBool operator ==(DBBool x, DBBool y) {
if (x.value == 0 || y.value == 0) return Null;
return x.value == y.value? True: False;
}
// Inequality operator. Returns Null if either operand is Null, otherwise
// returns True or False.
public static DBBool operator !=(DBBool x, DBBool y) {
if (x.value == 0 || y.value == 0) return Null;
return x.value != y.value? True: False;
}
// 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) {
return new DBBool(-x.value);
}
// 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) {
return new DBBool(x.value < y.value? x.value: y.value);
}
// 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) {
return new DBBool(x.value > y.value? x.value: y.value);
}
// Definitely true operator. Returns true if the operand is True, false
// otherwise.
public static bool operator true(DBBool x) {
return x.value > 0;
}
// Definitely false operator. Returns true if the operand is False, false
// otherwise.
public static bool operator false(DBBool x) {
return x.value < 0;
}
public override bool Equals(object obj) {
if (!(obj is DBBool)) return false;
return value == ((DBBool)obj).value;
}
public override int GetHashCode() {
return value;
}
public override string ToString() {
if (value > 0) return "DBBool.True";
if (value < 0) return "DBBool.False";
return "DBBool.Null";
}
}