OpCodes.Readonly Field
Definition
Important
Some information relates to prerelease product that may be substantially modified before it’s released. Microsoft makes no warranties, express or implied, with respect to the information provided here.
Specifies that the subsequent array address operation performs no type check at run time, and that it returns a managed pointer whose mutability is restricted.
public: static initonly System::Reflection::Emit::OpCode Readonly;
public static readonly System.Reflection.Emit.OpCode Readonly;
staticval mutable Readonly : System.Reflection.Emit.OpCode
Public Shared ReadOnly Readonly As OpCode
Field Value
Remarks
The following table lists the instruction's hexadecimal and Microsoft intermediate language (MSIL) assembly format, along with a brief reference summary:
Format | Assembly Format | Description |
---|---|---|
FE 1E | readonly. | Specify that the subsequent array address operation performs no type check at run time, and that it returns a managed pointer with restricted mutability. |
This prefix can only appear immediately preceding the ldelema
instruction and calls to the special Address
method on arrays. Its effect on the subsequent operation is twofold:
At run time, no type check operation is performed. Note that there is normally an implicit type check for the
ldelema
andstelem
instructions when used on reference type arrays. There is never a run-time type check for value classes, soreadonly
is a no-op in that case.The verifier treats the result of the address-of operation as a managed pointer with restricted mutability.
The pointer is said to have restricted mutability because the defining type controls whether the value can be mutated. For value classes that expose no public fields or methods that update the value in place, the pointer is read-only (hence the name of the prefix). In particular, the classes representing primitive types (for example, System.Int32) do not expose mutators and thus are read-only.
A managed pointer restricted in this fashion can be used only in the following ways:
As the
object
parameter for theldfld
,ldflda
,stfld
,call
, orconstrained callvirt
instructions.As the
pointer
parameter to theldobj
instruction or to one of theldind
instructions.As the
source
parameter to thecpobj
instruction.
All other operations disallowed, including the stobj
, initobj
, or mkrefany
operations, or any of the stind
instructions.
The purpose of the readonly
prefix is to avoid a type check when fetching an element from an array in generic code. For example, the expression arr[i].m()
, where the element type of the array arr
is a generic type that has been constrained to have an interface with method m
, might compile to the following MSIL.
ldloc arr
ldloc i
readonly.
ldelema !0 // Loads the pointer to the object.
… // Load the arguments to the call.
constrained. !0
callvirt m
Without the readonly
prefix, the ldelema
instruction would perform a type check in the case where !0 was a reference type. Not only is this type check inefficient, but it is semantically incorrect. The type check for ldelema
is an exact match, which is too strong. If the array held subclasses of type !0, the code above would fail the type check.
The address of the array element is fetched, instead of the element itself, in order to have a handle for arr[i]
that works for both value types and reference types, and thus can be passed to the constrained callvirt
instruction.
In general it would be unsafe to skip the run-time check if the array held elements of a reference type. To be safe, it is necessary to ensure that no modifications to the array are made through this pointer. The verifier rules ensure this. The restricted managed pointer can be passed as the object of instance method calls, so it is not strictly speaking read-only for value types, but there is no type safety problem for value types.
The following Emit method overload can use the readonly
opcode: