Language Specification Version 0 Notice



Download 3.2 Mb.
Page20/85
Date29.01.2017
Size3.2 Mb.
#10878
1   ...   16   17   18   19   20   21   22   23   ...   85

4.5Type parameters


A type parameter is an identifier designating a value type or reference type that the parameter is bound to at run-time.

type-parameter:
identifier

Since a type parameter can be instantiated with many different actual type arguments, type parameters have slightly different operations and restrictions than other types. These include:



  • A type parameter cannot be used directly to declare a base class (§10.2.4) or interface (§13.1.3).

  • The rules for member lookup on type parameters depend on the constraints, if any, applied to the type parameter. They are detailed in §7.3.

  • The available conversions for a type parameter depend on the constraints, if any, applied to the type parameter. They are detailed in §6.1.9 and §6.2.6.

  • The literal null cannot be converted to a type given by a type parameter, except if the type parameter is known to be a reference type (§6.1.9). However, a default expression (§7.5.13) can be used instead. In addition, a value with a type given by a type parameter can be compared with null using == and != (§7.9.6) unless the type parameter has the value type constraint.

  • A new expression (§7.5.10.1) can only be used with a type parameter if the type parameter is constrained by a constructor-constraint or the value type constraint (§10.1.5).

  • A type parameter cannot be used anywhere within an attribute.

  • A type parameter cannot be used in a member access (§7.5.4) or type name (§3.8) to identify a static member or a nested type.

  • In unsafe code, a type parameter cannot be used as an unmanaged-type (§18.2).

As a type, type parameters are purely a compile-time construct. At run-time, each type parameter is bound to a run-time type that was specified by supplying a type argument to the generic type declaration. Thus, the type of a variable declared with a type parameter will, at run-time, be a closed constructed type (§4.4.2). The run-time execution of all statements and expressions involving type parameters uses the actual type that was supplied as the type argument for that parameter.

4.6Expression tree types


Expression trees permit anonymous functions to be represented as data structures instead of executable code. Expression trees are values of expression tree types of the form System.Linq.Expressions.Expression, where D is any delegate type. For the remainder of this specification we will refer to these types using the shorthand Expression.

If a conversion exists from an anonymous function to a delegate type D, a conversion also exists to the expression tree type Expression. Whereas the conversion of an anonymous function to a delegate type generates a delegate that references executable code for the anonymous function, conversion to an expression tree type creates an expression tree representation of the anonymous function.

Expression trees are efficient in-memory data representations of anonymous functions and make the structure of the anonymous function transparent and explicit.

Just like a delegate type D, Expression is said to have parameter and return types, which are the same as those of D.

The following example represents an anonymous function both as executable code and as an expression tree. Because a conversion exists to Func, a conversion also exists to Expression>:

Func del = x => x + 1; // Code

Expression> exp = x => x + 1; // Data

Following these assignments, the delegate del references a method that returns x + 1, and the expression tree exp references a data structure that describes the expression x => x + 1.

The exact definition of the generic type Expression as well as the precise rules for constructing an expression tree when an anonymous function is converted to an expression tree type, are both outside the scope of this specification, and are described elsewhere.

Two things are important to make explicit:



  • Not all anonymous functions can be represented as expression trees. For instance, anonymous functions with statement bodies, and anonymous functions containing assignment expressions cannot be represented. In these cases, a conversion still exists, but will fail at compile time.

  • Expression offers an instance method Compile which produces a delegate of type D:

Func del2 = exp.Compile();

Invoking this delegate causes the code represented by the expression tree to be executed. Thus, given the definitions above, del and del2 are equivalent, and the following two statements will have the same effect:

int i1 = del(1);

int i2 = del2(1);

After executing this code, i1 and i2 will both have the value 2.

5.Variables


Variables represent storage locations. Every variable has a type that determines what values can be stored in the variable. C# is a type-safe language, and the C# compiler guarantees that values stored in variables are always of the appropriate type. The value of a variable can be changed through assignment or through use of the ++ and    operators.

A variable must be definitely assigned (§5.3) before its value can be obtained.

As described in the following sections, variables are either initially assigned or initially unassigned. An initially assigned variable has a well-defined initial value and is always considered definitely assigned. An initially unassigned variable has no initial value. For an initially unassigned variable to be considered definitely assigned at a certain location, an assignment to the variable must occur in every possible execution path leading to that location.

5.1Variable categories


C# defines seven categories of variables: static variables, instance variables, array elements, value parameters, reference parameters, output parameters, and local variables. The sections that follow describe each of these categories.

In the example

class A
{
public static int x;
int y;

void F(int[] v, int a, ref int b, out int c) {


int i = 1;
c = a + b++;
}
}

x is a static variable, y is an instance variable, v[0] is an array element, a is a value parameter, b is a reference parameter, c is an output parameter, and i is a local variable.


5.1.1Static variables


A field declared with the static modifier is called a static variable. A static variable comes into existence before execution of the static constructor (§10.12) for its containing type, and ceases to exist when the associated application domain ceases to exist.

The initial value of a static variable is the default value (§5.2) of the variable’s type.

For purposes of definite assignment checking, a static variable is considered initially assigned.

5.1.2Instance variables


A field declared without the static modifier is called an instance variable.

5.1.2.1Instance variables in classes


An instance variable of a class comes into existence when a new instance of that class is created, and ceases to exist when there are no references to that instance and the instance’s destructor (if any) has executed.

The initial value of an instance variable of a class is the default value (§5.2) of the variable’s type.

For the purpose of definite assignment checking, an instance variable of a class is considered initially assigned.

5.1.2.2Instance variables in structs


An instance variable of a struct has exactly the same lifetime as the struct variable to which it belongs. In other words, when a variable of a struct type comes into existence or ceases to exist, so too do the instance variables of the struct.

The initial assignment state of an instance variable of a struct is the same as that of the containing struct variable. In other words, when a struct variable is considered initially assigned, so too are its instance variables, and when a struct variable is considered initially unassigned, its instance variables are likewise unassigned.


5.1.3Array elements


The elements of an array come into existence when an array instance is created, and cease to exist when there are no references to that array instance.

The initial value of each of the elements of an array is the default value (§5.2) of the type of the array elements.

For the purpose of definite assignment checking, an array element is considered initially assigned.

5.1.4Value parameters


A parameter declared without a ref or out modifier is a value parameter.

A value parameter comes into existence upon invocation of the function member (method, instance constructor, accessor, or operator) or anonymous function to which the parameter belongs, and is initialized with the value of the argument given in the invocation. A value parameter normally ceases to exist upon return of the function member or anonymous function. However, if the value parameter is captured by an anonymous function (§7.14), its life time extends at least until the delegate or expression tree created from that anonymous function is eligible for garbage collection.

For the purpose of definite assignment checking, a value parameter is considered initially assigned.

5.1.5Reference parameters


A parameter declared with a ref modifier is a reference parameter.

A reference parameter does not create a new storage location. Instead, a reference parameter represents the same storage location as the variable given as the argument in the function member or anonymous function invocation. Thus, the value of a reference parameter is always the same as the underlying variable.

The following definite assignment rules apply to reference parameters. Note the different rules for output parameters described in §5.1.6.


  • A variable must be definitely assigned (§5.3) before it can be passed as a reference parameter in a function member or delegate invocation.

  • Within a function member or anonymous function, a reference parameter is considered initially assigned.

Within an instance method or instance accessor of a struct type, the this keyword behaves exactly as a reference parameter of the struct type (§7.5.7).

5.1.6Output parameters


A parameter declared with an out modifier is an output parameter.

An output parameter does not create a new storage location. Instead, an output parameter represents the same storage location as the variable given as the argument in the function member or delegate invocation. Thus, the value of an output parameter is always the same as the underlying variable.

The following definite assignment rules apply to output parameters. Note the different rules for reference parameters described in §5.1.5.


  • A variable need not be definitely assigned before it can be passed as an output parameter in a function member or delegate invocation.

  • Following the normal completion of a function member or delegate invocation, each variable that was passed as an output parameter is considered assigned in that execution path.

  • Within a function member or anonymous function, an output parameter is considered initially unassigned.

  • Every output parameter of a function member or anonymous function must be definitely assigned (§5.3) before the function member or anonymous function returns normally.

Within an instance constructor of a struct type, the this keyword behaves exactly as an output parameter of the struct type (§7.5.7).

5.1.7Local variables


A local variable is declared by a local-variable-declaration, which may occur in a block, a for-statement, a switch-statement or a using-statement; or by a foreach-statement or a specific-catch-clause for a try-statement.

The lifetime of a local variable is the portion of program execution during which storage is guaranteed to be reserved for it. This lifetime extends at least from entry into the block, for-statement, switch-statement, using-statement, foreach-statement, or specific-catch-clause with which it is associated, until execution of that block, for-statement, switch-statement, using-statement, foreach-statement, or specific-catch-clause ends in any way. (Entering an enclosed block or calling a method suspends, but does not end, execution of the current block, for-statement, switch-statement, using-statement, foreach-statement, or specific-catch-clause.) If the local variable is captured by an anonymous function (§7.14.4.1), its lifetime extends at least until the delegate or expression tree created from the anonymous function, along with any other objects that come to reference the captured variable, are eligible for garbage collection.

If the parent block, for-statement, switch-statement, using-statement, foreach-statement, or specific-catch-clause is entered recursively, a new instance of the local variable is created each time, and its local-variable-initializer, if any, is evaluated each time.

A local variable introduced by a local-variable-declaration is not automatically initialized and thus has no default value. For the purpose of definite assignment checking, a local variable introduced by a local-variable-declaration is considered initially unassigned. A local-variable-declaration may include a local-variable-initializer, in which case the variable is considered definitely assigned in its entire scope, except within the expression provided in the local-variable-initializer.

Within the scope of a local variableintroduced by a local-variable-declaration, it is a compile-time error to refer to that local variable in a textual position that precedes its local-variable-declarator. If the local variable declaration is implicit (§8.5.1), it is also an error to refer to the variable within its local-variable-declarator.

A local variable introduced by a foreach-statement or a specific-catch-clause is considered definitely assigned in its entire scope.

The actual lifetime of a local variable is implementation-dependent. For example, a compiler might statically determine that a local variable in a block is only used for a small portion of that block. Using this analysis, the compiler could generate code that results in the variable’s storage having a shorter lifetime than its containing block.

The storage referred to by a local reference variable is reclaimed independently of the lifetime of that local reference variable (§3.9).




Download 3.2 Mb.

Share with your friends:
1   ...   16   17   18   19   20   21   22   23   ...   85




The database is protected by copyright ©ininet.org 2022
send message

    Main page