Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Evaluation of a task-returning async functionСодержание книги
Поиск на нашем сайте
Invocation of a task-returning async function causes an instance of the returned task type to be generated. This is called the return task of the async function. The task is initially in an incomplete state. The async function body is then evaluated until it is either suspended (by reaching an await expression) or terminates, at which point control is returned to the caller, along with the return task. When the body of the async function terminates, the return task is moved out of the incomplete state: · If the function body terminates as the result of reaching a return statement or the end of the body, any result value is recorded in the return task, which is put into a succeeded state. · If the function body terminates as the result of an uncaught exception (§8.9.5) the exception is recorded in the return task which is put into a faulted state. Evaluation of a void-returning async function If the return type of the async function is void, evaluation differs from the above in the following way: Because no task is returned, the function instead communicates completion and exceptions to the current thread’s synchronization context. The exact definition of synchronization context is implementation-dependent, but is a representation of “where” the current thread is running. The synchronization context is notified when evaluation of a void-returning async function commences, completes successfully, or causes an uncaught exception to be thrown. This allows the context to keep track of how many void-returning async functions are running under it, and to decide how to propagate exceptions coming out of them.
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. As described in §4.1.4, 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, 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 (§11.4). Struct declarations A struct-declaration is a type-declaration (§9.6) that declares a new struct: struct-declaration: A struct-declaration consists of an optional set of attributes (§17), followed by an optional set of struct-modifiers (§11.1.1), 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 (§10.1.3), followed by an optional struct-interfaces specification (§11.1.2)), followed by an optional type-parameters-constraints-clauses specification (§10.1.5), followed by a struct-body (§11.1.4), optionally followed by a semicolon. Struct modifiers A struct-declaration may optionally include a sequence of struct modifiers: struct-modifiers: struct-modifier: 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 (§10.1). Partial modifier 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 §10.2. 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 implementations are discussed further in §13.4. Struct body The struct-body of a struct defines the members of the struct. struct-body: Struct members The members of a struct consist of the members introduced by its struct-member-declarations and the members inherited from the type System.ValueType. struct-member-declarations: struct-member-declaration: Except for the differences noted in §11.3, the descriptions of class members provided in §10.3 through §10.14 apply to struct members as well. Class and struct differences Structs differ from classes in several important ways: · Structs are value types (§11.3.1). · All struct types implicitly inherit from the class System.ValueType (§11.3.2). · Assignment to a variable of a struct type creates a copy of the value being assigned (§11.3.3). · 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 (§11.3.4). · Boxing and unboxing operations are used to convert between a struct type and object (§11.3.5). · The meaning of this is different for structs (§7.6.7). · Instance field declarations for a struct are not permitted to include variable initializers (§11.3.7). · A struct is not permitted to declare a parameterless instance constructor (§11.3.8). · A struct is not permitted to declare a destructor (§11.3.9). Value semantics 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. 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. 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 Node next; // error, Node directly depends on itself } 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; } 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. 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. 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 Point(int x, int y) { the code fragment Point a = new Point(10, 10); 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. Inheritance 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. 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 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. 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.17.1. Default values 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[] a = 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.2). 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. Structs should be designed to consider the default initialization state a valid state. In the example using System; struct KeyValuePair public KeyValuePair(string key, string value) { 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. Boxing and unboxing 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. 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 public override string ToString() { class Program static void Main() { The output of the program is: 1 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. For example, suppose an interface ICounter contains a method Increment which can be used to modify a value. 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 struct Counter: ICounter public override string ToString() { void ICounter.Increment() { class Program static void Main() { The first call to Increment modifies the value in the variable 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 For further details on boxing and unboxing, see §4.3. Meaning of this 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. Field initializers 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. This restriction applies only to instance fields. Static fields of a struct are permitted to include variable initializers. The example struct Point 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. 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.2). A struct can declare instance constructors having parameters. For example struct Point public Point(int x, int y) { Given the above 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 instance constructor is not permitted to include a constructor initializer of the form base(...). 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 (§5.3) at every location where the constructor returns. 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 public int X { public int Y { public Point(int x, int 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. Note, however, that if Point were a class instead of a struct, the instance constructor implementation would be permitted. 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 (§11.3.4) of struct types does not trigger the static constructor. (An example of this is the initial value of elements in an array.) Struct examples 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 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 public static readonly DBInt Null = new DBInt(); // When the defined field is true, this DBInt represents a known value int value; // Private instance constructor. Creates a DBInt with a known value. DBInt(int value) { // 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 public int Value { get { return 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 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 obj) { public override int GetHashCode() { public override string ToString() { Database boolean type 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. using System; public struct DBBool public static readonly DBBool Null = new DBBool(0); // 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) { // Properties to examine the value of a DBBool. Return true if this 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 public static implicit operator DBBool(bool x) { // Explicit conversion from DBBool to bool. Throws an exception if the public static explicit operator bool(DBBool x) { // Equality operator. Returns Null if either operand is Null, otherwise public static DBBool operator ==(DBBool x, DBBool y) { // Inequality operator. Returns Null if either operand is Null, otherwise public static DBBool operator!=(DBBool x, DBBool y) { // Logical negation operator. Returns True if the operand is False, Null public static DBBool operator!(DBBool x) { // Logical AND operator. Returns False if either operand is False, public static DBBool operator &(DBBool x, DBBool y) { // Logical OR operator. Returns True if either operand is True, otherwise public static DBBool operator |(DBBool x, DBBool y) { // Definitely true operator. Returns true if the operand is True, false public static bool operator true(DBBool x) { // Definitely false operator. Returns true if the operand is False, false public static bool operator false(DBBool x) { public override bool Equals(object obj) { public override int GetHashCode() { public override string ToString() { Arrays An array is a data structure that contains a number of variables which are accessed through computed indices. The variables contained in an array, also called the elements of the array, are all of the same type, and this type is called the element type of the array. An array has a rank which determines the number of indices associated with each array element. The rank of an array is also referred to as the dimensions of the array. An array with a rank of one is called a single-dimensional array. An array with a rank greater than one is called a multi-dimensional array. Specific sized multi-dimensional arrays are often referred to as two-dimensional arrays, three-dimensional arrays, and so on. Each dimension of an array has an associated length which is an integral number greater than or equal to zero. The dimension lengths are not part of the type of the array, but rather are established when an instance of the array type is created at run-time. The length of a dimension determines the valid range of indices for that dimension: For a dimension of length N, indices can range from 0 to N – 1 inclusive. The total number of elements in an array is the product of the lengths of each dimension in the array. If one or more of the dimensions of an array have a length of zero, the array is said to be empty. The element type of an array can be any type, including an array type. Array types An array type is written as a non-array-type followed by one or more rank-specifiers: array-type: non-array-type: rank-specifiers: rank-specifier: dim-separators: A non-array-type is any type that is not itself an array-type. The rank of an array type is given by the leftmost rank-specifier in the array-type: A rank-specifier indicates that the array is an array with a rank of one plus the number of “,” tokens in the rank-specifier. The element type of an array type is the type that results from deleting the leftmost rank-specifier: · An array type of the form T[R] is an array with rank R and a non-array element type T. · An array type of the form T[R][R1]...[RN] is an array with rank R and an element type T[R1]...[RN]. In effect, the rank-specifiers are read from left to right before the final non-array element type. The type int[][,,][,] is a single-dimensional array of three-dimensional arrays of two-dimensional arrays of int. At run-time, a value of an array type can be null or a reference to an instance of that array type. The System.Array type The type System.Array is the abstract base type of all array types. An implicit reference conversion (§6.1.6) exists from any array type to System.Array, and an explicit reference conversion (§6.2.4) exists from System.Array to any array type. Note that System.Array is not itself an array-type. Rather, it is a class-type from which all array-types are derived. At run-time, a value of type System.Array can be null or a reference to an instance of any array type.
|
||||
Последнее изменение этой страницы: 2016-08-10; просмотров: 229; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.188.180.254 (0.012 с.) |