7 Types and Signatures


The metadata provides mechanisms to both define types and reference types. Partition II, section 9 describes the metadata associated with a type definition, regardless of whether the type is an interface, class, or a value type.

The mechanism used to reference types is divided into two parts. The first is the creation of a logical description of user-defined types that are referenced but (typically) not defined in the current module. These are stored in a logical table in the metadata (see Partition II, section 21.35).

The second is a signature that encodes one or more type references, along with a variety of modifiers. The grammar non-terminal <type> describes an individual entry in a signature. The encoding of a signature is specified in Partition II, section 22.1.15.

ANNOTATION

Type definitions are the heart of the CLI. There are built-in types, for which the VES must create a definition on declaration; class types, which are defined with one of the base library classes; global methods, which are methods that are not part of a class; managed and unmanaged pointers; and arrays. Like built-in types, both kinds of pointers and arrays are defined by the VES upon declaration, without a specific definition. The grammar also allows both optional and required modifiers to types.


7.1 Types

The following grammar completely specifies all built-in types, including pointer types of the CLI system. It also shows the syntax for user-defined types that can be defined in the CLI system:

<type> ::=

Description

Section in Partition II

 

bool

Boolean.

7.2

| boxed <typeReference>

Boxed user-defined value type.

 

| char

16-bit Unicode code point.

7.2

| class <typeReference>

User-defined reference type.

7.3

| float32

32-bit floating point number.

7.2

| float64

64-bit floating point number.

7.2

| int8

Signed 8-bit integer.

7.2

| int16

Signed 16-bit integer.

7.2

| int32

Signed 32-bit integer.

7.2

| int64

Signed 64-bit integer.

7.2

 | method <callConv> <type> *          ( <parameters> ) 

Method pointer.

13.5

| native int

Signed integer whose size varies depending on platform (32- or 64-bit).

7.2

| native unsigned int

Unsigned integer whose size varies depending on platform (32- or 64-bit).

7.2

| object

See System.Object in the .NET Framework Standard Library Annotated Reference.

[7.2]

| string

See System.String in the .NET Framework Standard Library Annotated Reference.

[7.2]

| <type> &

Managed pointer to <type>. <type> shall not be a managed pointer type or typedref.

13.4

| <type> *

Unmanaged pointer to <type>.

13.4

| <type> [ [<bound> [,<bound>]*] ]

Array of <type> with optional rank (number of dimensions) and bounds.

13.1 and 13.2

| <type> modopt ( <typeReference> )

Custom modifier that may be ignored by the caller.

7.1.1

| <type> modreq ( <typeReference> )

Custom modifier that the caller shall understand.

7.1.1

| <type> pinned

For local variables only. The garbage collector shall not move the referenced value.

7.1.2

| typedref

Typed reference, created by mkrefany and used by refanytype or refanyval.

7.2

| valuetype <typeReference>

User-defined value type (unboxed).

12.1

| unsigned int8

Unsigned 8-bit integers.

7.2

| unsigned int16

Unsigned 16-bit integers.

7.2

| unsigned int32

Unsigned 32-bit integers.

7.2

| unsigned int64

Unsigned 64-bit integers.

7.2

| void

No type. Only allowed as a return type or as part of void *.

 

In several situations the grammar permits the use of a slightly simpler mechanism for specifying types, by just allowing type names (e.g., "System.GC") to be used instead of the full algebra (e.g., "class System.GC"). These are called type specifications:

<typeSpec> ::=

Section in Partition II

 

[ [.module] <dottedname> ]

7.3

| <typeReference>

7.3

| <type>

7.1

ANNOTATION

The <typedref> is an elegant construct not currently used by any languages. It requires that both the reference to an address and its data type will be passed. It is an artifact of paramvalues, which were part of earlier versions of Microsoft Visual Basic. Although no longer available in Visual Basic, it would be useful in a language with dynamic types, or languages with variable-length argument lists.


7.1.1 modreq and modopt

Custom modifiers, defined using modreq ("required modifier") and modopt ("optional modifier"), are similar to custom attributes (see Partition II, section 20) except that modifiers are part of a signature rather than attached to a declaration. Each modifer associates a type reference with an item in the signature.

The CLI itself shall treat required and optional modifiers in the same manner. Two signatures that differ only by the addition of a custom modifier (required or optional) shall not be considered to match. Custom modifiers have no other effect on the operation of the VES.

RATIONALE

The distinction between required and optional modifiers is important to tools other than the CLI that deal with the metadata, typically compilers and program analyzers. A required modifier indicates that there is a special semantics to the modified item that should not be ignored, while an optional modifier can simply be ignored.

For example, the concept of const in the C programming language can be modelled with an optional modifier, since the caller of a method that has a constant parameter need not treat it in any special way. On the other hand, a parameter that shall be copy constructed in C++ shall be marked with a required custom attribute, since it is the caller who makes the copy.


ANNOTATION

The modopt construct tells the compiler that there is more information about the type, but the information is compiler-specific, and it will have no effect on compilers that do not recognize the modifer. The modreq modifer, on the other hand, requires any compiler to recognize the modifer. If it does not, the compiler cannot use the parameter and must return an error.


7.1.2 pinned

The signature encoding for pinned shall appear only in signatures that describe local variables (see Partition II, section 14.4.1.3). While a method with a pinned local variable is executing, the VES shall not relocate the object to which the local refers. That is, if the implementation of the CLI uses a garbage collector that moves objects, the collector shall not move objects that are referenced by an active pinned local variable.

RATIONALE

If unmanaged pointers are used to dereference managed objects, these objects shall be pinned. This happens, for example, when a managed object is passed to a method designed to operate with unmanaged data.


ANNOTATION

Pinning is necessary to enable unmanaged code (code that does not deal with the garbage collector) to work with managed objects. Managed references (<type>&) are tied to objects, so if the object moves by virtue of a garbage collector, the reference moves with it. In contrast, an unmanaged reference (unmanaged pointer) is tied to a specific address. If the object to which it points moves, the reference stays, and unpredictable results follow. Pinning allows the programmer to fix the object to which the reference points. This is generally used for machine assembly language or C and C++ programs that have been compiled for CLI execution.

Other than dealing with unmanaged programs, pinning is not generally used, because a garbage collector must move things around the pinned object. This would make the garbage collector slower, make holes in memory, etc.


7.2 Built-in Types

The CLI built-in types have corresponding value types defined in the Base Class Library. They shall be referenced in signatures only using their special encodings (i.e., not using the general-purpose valuetype <typeReference> syntax). Partition I [section 8.2.2] specifies the built-in types.

ANNOTATION

Built-in types must be defined by the VES upon their declaration, and they do not require the specific definition required of most types. The built-in numeric types (which are value types) are shown in the following table, copied here from Partition I, section 8.2.2:


Name in CIL Assembler

CLS Type?

Name in Class Library (see the .NET Framework Standard Library Annotated Reference)

Description

bool

Yes

System.Boolean

True/false value

char

Yes

System.Char

Unicode 16-bit char

object

Yes

System.Object

Object or boxed value type

string

Yes

System.String

Unicode string

float32

Yes

System.Single

IEC 60559:1989 32-bit float

float64

Yes

System.Double

IEC 60559:1989 64-bit float

int8

No

System.SByte

Signed 8-bit integer

int16

Yes

System.Int16

Signed 16-bit integer

int32

Yes

System.Int32

Signed 32-bit integer

int64

Yes

System.Int64

Signed 64-bit integer

native int

Yes

System.IntPtr

Signed integer, native size

native unsigned int

No

System.UIntPtr

Unsigned integer, native size

typedref

No

System.TypedReference

Pointer plus runtime type

unsigned int8

Yes

System.Byte

Unsigned 8-bit integer

unsigned int16

No

System.UInt16

Unsigned 16-bit integer

unsigned int32

No

System.UInt32

Unsigned 32-bit integer

unsigned int64

No

System.UInt64

Unsigned 64-bit integer

7.3 References to User-Defined Types (<typeReference>)

User-defined types are referenced either using their full name and a resolution scope or (if one is available in the same module) a type definition (see Partition II, section 9).

A <typeReference> is used to capture the full name and resolution scope.

<typeReference> ::=

 

[<resolutionScope>] <dottedname> [/ <dottedname>]*

<resolutionScope> ::=

 

[ .module <filename> ]

| [ <assemblyRefName> ]

<assemblyRefName> ::=

Section in Partition II

 

<dottedname>

5.3

The following resolution scopes are specified for un-nested types:

  • Current module (and, hence, assembly). This is the most common case and is the default if no resolution scope is specified. The type shall be resolved to a definition only if the definition occurs in the same module as the reference.

    NOTE

    A type reference that refers to a type in the same module and assembly is better represented using a type definition. Where this is not possible (for example, when referencing a nested type that has compilercontrolled accessibility) or convenient (for example, in some one-pass compilers), a type reference is equivalent and may be used.


  • Different module, current assembly. The resolution scope shall be a module reference syntactically reprented using the notation [.module <filename>]. The type shall be resolved to a definition only if the referenced module (see Partition II, section 6.4) and type (see Partition II, section 6.7) have been declared by the current assembly and hence have entries in the assembly's manifest. Note that in this case the manifest is not physically stored with the referencing module.

  • Different assembly. The resolution scope shall be an assembly reference syntactically represented using the notation [<assemblyRefName>]. The referenced assembly shall be declared in the manifest for the current assembly (see Partition II, section 6.3), the type shall be declared in the referenced assembly's manifest, and the type shall be marked as exported from that assembly (see Partition II, sections 6.7 and 9.1.1).

  • For nested types, the resolution scope is always the enclosing type (see Partition II, section 9.6). This is indicated syntactically by using a slash ("/") to separate the enclosing type name from the nested type's name.

     

    Example (informative): The proper way to refer to a type defined in the Base Class Library. The name of the type graphics/ccc.gif is System.Console, and it is found in the assembly named mscorlib. .assembly extern mscorlib { } .class [mscorlib]System.Console A reference to the type named C.D in the module named x in the current assembly. .module extern x .class [.module x]C.D A reference to the type named C nested inside of the type named Foo.Bar in another graphics/ccc.gif assembly, named MyAssembly. .assembly extern MyAssembly { } .class [MyAssembly]Foo.Bar/C

7.4 Native Data Types

Some implementations of the CLI will be hosted on top of existing operating systems or runtime platforms that specify data types required to perform certain functions. The metadata allows interaction with these native data types by specifying how the built-in and user-defined types of the CLI are to be marshalled to and from native data types. This marshalling information can be specified (using the keyword marshal) for

  • The return type of a method, indicating that a native data type is actually returned and shall be marshalled back into the specified CLI data type

  • A parameter to a method, indicating that the CLI data type provided by the caller shall be marshalled into the specified native data type (if the parameter is passed by reference, the updated value shall be marshalled back from the native data type into the CLI data type when the call is completed)

  • A field of a user-defined type, indicating that any attempt to pass the object in which it occurs to platform methods shall make a copy of the object, replacing the field by the specified native data type (if the object is passed by reference, then the updated value shall be marshalled back when the call is completed)

The following table lists all native types supported by the CLI and provides a description for each of them. A more complete description can be found in the .NET Framework Standard Library Annotated Reference in the definition of the enum System.Runtime. Interopservices.UnmanagedType, which provides the actual values used to encode the types. All encoding values from 0 through 63 are reserved for backward compatibility with existing implementations of the CLI. Values 64 through 127 are reserved for future use in this and related standards.

<nativeType> ::=

Description

Name in Class Library

[ ]

Native array. Type and size are determined at runtime from the actual marshalled array.

LPArray

| bool

Boolean. 4-byte integer value where a non-zero value represents TRUE and 0 represents FALSE.

Bool

| float32

32-bit floating point number.

FLOAT32

| float64

64-bit floating point number.

FLOAT64

| [unsigned] int

Signed or unsigned integer, sized to hold a pointer on the platform.

SysUInt or SysInt

| [unsigned] int8

Signed or unsigned 8-bit integer.

unsigned int8 or int8

| [unsigned] int16

Signed or unsigned 16-bit integer.

unsigned int16 or int16

| [unsigned] int32

Signed or unsigned 32-bit integer.

unsigned int32 or int32

| [unsigned] int64

Signed or unsigned 64-bit integer.

unsigned int64 or int64

| lpstr

A pointer to a null terminated array of ANSI characters. Code page is implementation specific.

LPStr

| lptstr

A pointer to a null terminated array of platform characters (ANSI or Unicode). Code page and character encoding are implementation-specific.

LPTStr

| lpvoid

An untyped pointer; platform specifies size.

LPVoid

| lpwstr

A pointer to a null terminated array of Unicode characters. Character encoding is implementation-specific.

LPWStr

| method

A function pointer.

FunctionPtr

| <nativeType> [ ]

Array of <nativeType>. The length is determined at runtime by the size of the actual marshalled array.

LPArray

| <nativeType> [ <int32> ]

Array of <nativeType> of length <int32>.

LPArray

| <nativeType> [ + <int32> ]

Array of <nativeType> with runtime-supplied element size. The int32 specifies a parameter to the current method (counting from parameter number 0) that, at runtime, will contain the size of an element of the array in bytes. Can only be applied to methods, not fields.

LPArray

| <nativeType> [ <int32> + <int32> ]

Array of <nativeType> with runtime-supplied element size. The first int32 specifies the number of elements in the array. The second int32 specifies which parameter to the current method (counting from parameter number 1) will specify the additional number of elements in the array. Can only be applied to methods, not fields.

LPArray

ANNOTATION

Implementation-Specific (Microsoft): The Microsoft implementation supports a richer set of types to describe marshalling between Windows native types and COM. These additional options are listed in the following table:

<nativeType> ::=

Description

Name in Class Library

| as any

Determines the type of an object at runtime and marshals the object as that type.

AsAny

| byvalstr

A string in a fixed-length buffer.

VBByRefStr

| custom ( <QSTRING>, <QSTRING> )

Custom marshaller. The first string is the name of the marshalling class, using the string conventions of Reflection.Emit to specify the assembly and/or module. The second is an arbitrary string passed to the marshaller at runtime to identify the form of marshalling required.

CustomMarshaler

| fixed array [ <int32> ]

A fixed-size array of length <int32> bytes.

ByValArray

| fixed sysstring [ <int32> ]

A fixed-size system string of length <int32>. This can only be applied to fields, and a separate attribute specifies the encoding of the string.

ByValTStr

| lpstruct

A pointer to a C-style structure. Used to marshal managed formatted types.

LPStruct

| struct

A C-style structure, used to marshal managed formatted types.

Struct


 

Example (informative): .method int32 M1( int32 marshal(int32), bool[] marshal(bool[5]) ) Method M1 takes two arguments: an int32, and an array of five bools ++++++++++ .method int32 M2( int32 marshal(int32), bool[] marshal(bool[+1]) ) Method M2 takes two arguments: an int32, and an array of bools: the number of elements in graphics/ccc.gif that array is given by the value of the first parameter ++++++++++ .method int32 M3( int32 marshal(int32), bool[] marshal(bool[7+1]) ) Method M3 takes two arguments: an int32, and an array of bools: the number of elements in graphics/ccc.gif that array is given as 7 plus the value of the first parameter


The Common Language Infrastructure Annotated Standard (Microsoft. NET Development Series)
The Common Language Infrastructure Annotated Standard (Microsoft. NET Development Series)
ISBN: N/A
EAN: N/A
Year: 2002
Pages: 121

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net