16 Structs
16.1 General
Las estructuras son similares a las clases de que representan estructuras de datos que pueden contener miembros de datos y miembros de función. Sin embargo, a diferencia de las clases, las estructuras son tipos de valor y no requieren asignación de montón. Una variable de un struct
tipo contiene directamente los datos de struct
, mientras que una variable de un tipo de clase contiene una referencia a los datos, el último conocido como objeto .
Nota: Las estructuras son especialmente útiles para estructuras de datos pequeñas que tienen semántica de valor. Los números complejos, los puntos de un sistema de coordenadas o los pares clave-valor de un diccionario son buenos ejemplos de structs. La clave de estas estructuras de datos es que tienen pocos miembros de datos, que no requieren el uso de la semántica de herencia o referencia, sino que se pueden implementar convenientemente mediante la semántica de valores donde la asignación copia el valor en lugar de la referencia. nota final
Como se describe en §8.3.5, los tipos simples proporcionados por C#, como int
, double
y bool
, son, de hecho, todos los tipos de estructura.
16.2 Declaraciones de estructura
16.2.1 General
Un struct_declaration es un type_declaration (§14.7) que declara una nueva estructura:
struct_declaration
: attributes? struct_modifier* 'ref'? 'partial'? 'struct'
identifier type_parameter_list? struct_interfaces?
type_parameter_constraints_clause* struct_body ';'?
;
Un struct_declaration consta de un conjunto opcional de atributos (§22), seguido de un conjunto opcional de struct_modifiers (§16.2.2), seguido de un modificador opcional ref
(§16.2.3), seguido de un modificador parcial opcional (§15.2.7), seguido de la palabra clave struct
y un identificador que asigna el nombre a la estructura, seguido de una especificación de type_parameter_list opcional (§15.2.3)), seguido de una especificación opcional de struct_interfaces (§16.2.5), seguida de una especificación opcional de cláusulas type_parameter_constraints (§15.2.5), seguida de un struct_body (§16.2.6), opcionalmente seguido de un punto y coma.
Una declaración de estructura no proporcionará una type_parameter_constraints_clauses a menos que también proporcione una type_parameter_list.
Una declaración de estructura que proporciona un type_parameter_list es una declaración de estructura genérica. Además, cualquier estructura anidada dentro de una declaración de clase genérica o una declaración de estructura genérica es una declaración de estructura genérica, ya que se proporcionarán argumentos de tipo para el tipo contenedor para crear un tipo construido (§8.4).
Una declaración de estructura que incluya una ref
palabra clave no tendrá una parte struct_interfaces .
Modificadores Struct 16.2.2
Un struct_declaration puede incluir opcionalmente una secuencia de struct_modifiers:
struct_modifier
: 'new'
| 'public'
| 'protected'
| 'internal'
| 'private'
| 'readonly'
| unsafe_modifier // unsafe code support
;
unsafe_modifier (§23.2) solo está disponible en código no seguro (§23).
Es un error en tiempo de compilación para que el mismo modificador aparezca varias veces en una declaración de estructura.
Excepto para readonly
, los modificadores de una declaración de estructura tienen el mismo significado que los de una declaración de clase (§15.2.2).
El readonly
modificador indica que el struct_declaration declara un tipo cuyas instancias son inmutables.
Una estructura de solo lectura tiene las siguientes restricciones:
- Cada uno de sus campos de instancia también se declarará
readonly
. - Ninguna de sus propiedades de instancia tendrá un set_accessor_declaration (§15.7.3).
- No declarará ningún evento similar a campo (§15.8.2).
Cuando una instancia de una estructura de solo lectura se pasa a un método, se this
trata como un argumento o parámetro de entrada, que no permite el acceso de escritura a cualquier campo de instancia (excepto por constructores).
Modificador Ref 16.2.3 Ref
El ref
modificador indica que el struct_declaration declara un tipo cuyas instancias se asignan en la pila de ejecución. Estos tipos se denominan tipos de estructura ref. El ref
modificador declara que las instancias pueden contener campos de tipo ref y no se copiarán fuera de su contexto seguro (§16.4.12). Las reglas para determinar el contexto seguro de una estructura ref se describen en §16.4.12.
Se trata de un error en tiempo de compilación si se usa un tipo de estructura ref en cualquiera de los contextos siguientes:
- Como tipo de elemento de una matriz.
- Como el tipo declarado de un campo de una clase o una estructura que no tiene el
ref
modificador . - La conversión boxeada en
System.ValueType
oSystem.Object
. - Como argumento de tipo.
- Como el tipo de un elemento de tupla.
- Un método asincrónico.
- Iterador.
- No hay ninguna conversión de un
ref struct
tipo al tipoobject
o al tipoSystem.ValueType
. - No
ref struct
se declarará un tipo para implementar ninguna interfaz. - No se llamará a un método de instancia declarado en
object
o en peroSystem.ValueType
no invalidado en unref struct
tipo con un receptor de eseref struct
tipo. - Un método de instancia de un
ref struct
tipo no se capturará mediante la conversión de grupo de métodos a un tipo delegado. - Una estructura ref no se capturará mediante una expresión lambda ni una función local.
Nota: Un
ref struct
no declararáasync
métodos de instancia ni usará unayield return
instrucción oyield break
dentro de un método de instancia, ya que el parámetro implícitothis
no se puede usar en esos contextos. nota final
Estas restricciones garantizan que una variable de ref struct
tipo no haga referencia a la memoria de pila que ya no sea válida o a variables que ya no sean válidas.
16.2.4 Modificador parcial
El partial
modificador indica que este struct_declaration es una declaración de tipo parcial. Varias declaraciones de estructura parciales con el mismo nombre dentro de un espacio de nombres o declaración de tipo envolvente se combinan para formar una declaración de estructura, siguiendo las reglas especificadas en §15.2.7.
Interfaces struct de 16.2.5
Una declaración de estructura puede incluir una especificación struct_interfaces , en cuyo caso se dice que la estructura implementa directamente los tipos de interfaz especificados. Para un tipo de estructura construido, incluido un tipo anidado declarado dentro de una declaración de tipo genérico (§15.3.9.7), cada tipo de interfaz implementado se obtiene sustituyendo, por cada type_parameter en la interfaz especificada, el type_argument correspondiente del tipo construido.
struct_interfaces
: ':' interface_type_list
;
El control de interfaces en varias partes de una declaración de estructura parcial (§15.2.7) se describe más adelante en §15.2.4.3.
Las implementaciones de interfaz se describen más adelante en §18.6.
Cuerpo de estructura 16.2.6
El struct_body de un struct define los miembros de la estructura.
struct_body
: '{' struct_member_declaration* '}'
;
16.3 Miembros de Struct
Los miembros de una estructura constan de los miembros introducidos por sus struct_member_declarations y los miembros heredados del tipo 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
| fixed_size_buffer_declaration // unsafe code support
;
fixed_size_buffer_declaration (§23.8.2) solo está disponible en código no seguro (§23).
Nota: Todos los tipos de class_member_declarationexcepto finalizer_declaration también se struct_member_declarations. nota final
A excepción de las diferencias indicadas en §16.4, las descripciones de los miembros de clase proporcionados en §15.3 a §15.12 también se aplican a los miembros struct.
16.4 Diferencias de clase y estructura
16.4.1 General
Las estructuras difieren de las clases de varias maneras importantes:
- Las estructuras son tipos de valor (§16.4.2).
- Todos los tipos de estructura heredan implícitamente de la clase
System.ValueType
(§16.4.3). - La asignación a una variable de un tipo de estructura crea una copia del valor que se asigna (§16.4.4).
- El valor predeterminado de un struct es el valor generado estableciendo todos los campos en su valor predeterminado (§16.4.5).
- Las operaciones de conversión boxing y unboxing se usan para convertir entre un tipo de estructura y determinados tipos de referencia (§16.4.6).
- El significado de es diferente dentro de
this
los miembros de estructura (§16.4.7). - Las declaraciones de campo de instancia de un struct no pueden incluir inicializadores de variables (§16.4.8).
- No se permite que un struct declare un constructor de instancia sin parámetros (§16.4.9).
- No se permite que un struct declare un finalizador.
16.4.2 Semántica de valores
Las estructuras son tipos de valor (§8.3) y se dice que tienen semántica de valor. Las clases, por otro lado, son tipos de referencia (§8.2) y se dice que tienen semántica de referencia.
Una variable de un tipo de estructura contiene directamente los datos de la estructura, mientras que una variable de un tipo de clase contiene una referencia a un objeto que contiene los datos. Cuando un struct B
contiene un campo de instancia de tipo A
y A
es un tipo de estructura, es un error en tiempo de compilación para A
que dependa B
de o de un tipo construido a partir de B
. A struct X
depende directamente de una estructura Y
si X
contiene un campo de instancia de tipo Y
. Dada esta definición, el conjunto completo de structs sobre los que depende una estructura es el cierre transitivo del elemento directamente depende de la relación.
Ejemplo:
struct Node { int data; Node next; // error, Node directly depends on itself }
es un error porque
Node
contiene un campo de instancia de su propio tipo. Otro ejemplostruct A { B b; } struct B { C c; } struct C { A a; }
es un error porque cada uno de los tipos
A
,B
yC
dependen entre sí.ejemplo final
Con las clases, es posible que dos variables hagan referencia al mismo objeto y, por tanto, es posible que las operaciones de una variable afecten al objeto al que hace referencia la otra variable. Con structs, las variables tienen su propia copia de los datos (excepto en el caso de los parámetros by-reference) y no es posible que las operaciones de una afecten a la otra. Además, excepto cuando se aceptan valores NULL explícitamente (§8.3.12), no es posible que los valores de un tipo de estructura sean null
.
Nota: Si una estructura contiene un campo de tipo de referencia, otras operaciones pueden modificar el contenido del objeto al que se hace referencia. Sin embargo, el valor del propio campo, es decir, el objeto al que hace referencia, no se puede cambiar a través de una mutación de un valor de estructura diferente. nota final
Ejemplo: dado lo siguiente
struct Point { public int x, y; public Point(int x, int y) { this.x = x; this.y = y; } } class A { static void Main() { Point a = new Point(10, 10); Point b = a; a.x = 100; Console.WriteLine(b.x); } }
la salida es
10
. La asignación dea
parab
crea una copia del valor yb
, por tanto, no se ve afectada por la asignación aa.x
. En su lugar, se habíaPoint
declarado como una clase, la salida sería100
porquea
yb
haría referencia al mismo objeto.ejemplo final
16.4.3 Herencia
Todos los tipos de estructura heredan implícitamente de la clase System.ValueType
, que, a su vez, hereda de la clase object
. Una declaración de estructura puede especificar una lista de interfaces implementadas, pero no es posible que una declaración de estructura especifique una clase base.
Los tipos de estructura nunca son abstractos y siempre están sellados implícitamente. Por lo tanto, los abstract
modificadores y sealed
no se permiten en una declaración de estructura.
Puesto que no se admite la herencia para estructuras, la accesibilidad declarada de un miembro de estructura no puede ser protected
, private protected
o protected internal
.
Los miembros de función de una estructura no pueden ser abstractos o virtuales, y el override
modificador solo puede invalidar los métodos heredados de System.ValueType
.
16.4.4 Asignación
La asignación a una variable de un tipo de estructura crea una copia del valor que se asigna. Esto difiere de la asignación a una variable de un tipo de clase, que copia la referencia, pero no el objeto identificado por la referencia.
De forma similar a una asignación, cuando se pasa un struct como parámetro de valor o se devuelve como resultado de un miembro de función, se crea una copia de la estructura. Una estructura se puede pasar por referencia a un miembro de función mediante un parámetro by-reference.
Cuando una propiedad o indexador de un struct es el destino de una asignación, la expresión de instancia asociada a la propiedad o el acceso al indexador se clasificará como una variable. Si la expresión de instancia se clasifica como un valor, se produce un error en tiempo de compilación. Esto se describe con más detalle en §12.21.2.
16.4.5 Valores predeterminados
Como se describe en §9.3, varios tipos de variables se inicializan automáticamente en su valor predeterminado cuando se crean. Para variables de tipos de clase y otros tipos de referencia, este valor predeterminado es null
. Sin embargo, dado que las estructuras son tipos de valor que no pueden ser null
, el valor predeterminado de un struct es el valor generado estableciendo todos los campos de tipo de valor en su valor predeterminado y todos los campos de tipo de referencia en null
.
Ejemplo: Hacer referencia a la
Point
estructura declarada anteriormente, el ejemploPoint[] a = new Point[100];
inicializa cada
Point
una de las matrices en el valor generado estableciendo losx
campos yy
en cero.ejemplo final
El valor predeterminado de una estructura corresponde al valor devuelto por el constructor predeterminado de la estructura (§8.3.3). A diferencia de una clase, no se permite que un struct declare un constructor de instancia sin parámetros. En su lugar, cada estructura tiene implícitamente un constructor de instancia sin parámetros, que siempre devuelve el valor resultante de establecer todos los campos en sus valores predeterminados.
Nota: Las estructuras deben diseñarse para considerar el estado de inicialización predeterminado un estado válido. En el ejemplo
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; } }
El constructor de instancia definido por el usuario protege contra
null
los valores solo en los que se llama explícitamente. En los casos en los que unaKeyValuePair
variable está sujeta a la inicialización del valor predeterminado, loskey
campos yvalue
seránnull
y la estructura debe estar preparada para controlar este estado.nota final
16.4.6 Boxing y unboxing
Un valor de un tipo de clase se puede convertir al tipo object
o a un tipo de interfaz implementado por la clase simplemente tratando la referencia como otro tipo en tiempo de compilación. Del mismo modo, un valor de tipo object
o un valor de un tipo de interfaz se puede convertir de nuevo a un tipo de clase sin cambiar la referencia (pero, por supuesto, se requiere una comprobación de tipo en tiempo de ejecución en este caso).
Dado que los structs no son tipos de referencia, estas operaciones se implementan de forma diferente para los tipos de estructura. Cuando se convierte un valor de un tipo de estructura en determinados tipos de referencia (como se define en §10.2.9), se realiza una operación de conversión boxing. Del mismo modo, cuando se convierte un valor de determinados tipos de referencia (como se define en §10.3.7) a un tipo de estructura, se realiza una operación de unboxing. Una diferencia clave de las mismas operaciones en los tipos de clase es que boxing y unboxing copia el valor de estructura en o fuera de la instancia boxed.
Nota: Por lo tanto, después de una operación de conversión boxing o unboxing
struct
, los cambios realizados en la caja no se reflejan en el cuadro .struct
nota final
Para obtener más información sobre la conversión boxing y unboxing, consulte §10.2.9 y §10.3.7.
16.4.7 Significado de esto
El significado de this
en un struct difiere del significado de this
en una clase, como se describe en §12.8.14. Cuando un tipo de estructura invalida un método virtual heredado de System.ValueType
(como Equals
, GetHashCode
o ToString
), la invocación del método virtual a través de una instancia del tipo de estructura no hace que se produzca la conversión boxing. Esto es cierto incluso cuando la estructura se usa como parámetro de tipo y la invocación se produce a través de una instancia del tipo de parámetro de tipo.
Ejemplo:
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>(); }
La salida del programa es:
1 2 3
Aunque es un estilo incorrecto para
ToString
tener efectos secundarios, en el ejemplo se muestra que no se produjo ninguna conversión boxing para las tres invocaciones dex.ToString()
.ejemplo final
De forma similar, la conversión boxing nunca se produce implícitamente al acceder a un miembro en un parámetro de tipo restringido cuando el miembro se implementa dentro del tipo de valor. Por ejemplo, supongamos que una interfaz ICounter
contiene un método Increment
, que se puede usar para modificar un valor. Si ICounter
se usa como restricción, se llama a la implementación del Increment
método con una referencia a la variable en la que Increment
se llamó, nunca una copia boxing.
Ejemplo:
interface ICounter { void Increment(); } struct Counter : ICounter { int value; public override string ToString() => 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>(); }
La primera llamada a
Increment
modifica el valor de la variablex
. Esto no equivale a la segunda llamada aIncrement
, que modifica el valor en una copia boxed dex
. Por lo tanto, la salida del programa es:0 1 1
ejemplo final
Inicializadores de campo 16.4.8
Como se describe en §16.4.5, el valor predeterminado de un struct consta del valor resultante de establecer todos los campos de tipo de valor en su valor predeterminado y todos los campos de tipo de referencia en null
. Por este motivo, una estructura no permite que las declaraciones de campo de instancia incluyan inicializadores de variables. Esta restricción solo se aplica a los campos de instancia. Los campos estáticos de una estructura pueden incluir inicializadores de variables.
Ejemplo: lo siguiente
struct Point { public int x = 1; // Error, initializer not permitted public int y = 1; // Error, initializer not permitted }
se produce un error porque las declaraciones de campo de instancia incluyen inicializadores de variables.
ejemplo final
16.4.9 Constructores
A diferencia de una clase, no se permite que un struct declare un constructor de instancia sin parámetros. En su lugar, cada estructura tiene implícitamente un constructor de instancia sin parámetros, que siempre devuelve el valor resultante de establecer todos los campos de tipo de valor en su valor predeterminado y todos los campos de tipo de referencia en null
(§8.3.3). Un struct puede declarar constructores de instancia que tienen parámetros.
Ejemplo: dado lo siguiente
struct Point { int x, y; public Point(int x, int y) { this.x = x; this.y = y; } } class A { static void Main() { Point p1 = new Point(); Point p2 = new Point(0, 0); } }
las instrucciones crean un
Point
conx
ey
inicializado en cero.ejemplo final
No se permite que un constructor de instancia de estructura incluya un inicializador de constructor del formulario base(
argument_list)
, donde argument_list es opcional.
El this
parámetro de un constructor de instancia de estructura corresponde a un parámetro de salida del tipo de estructura. Por lo tanto, this
se asignará definitivamente (§9.4) en cada ubicación donde vuelva el constructor. Del mismo modo, no se puede leer (incluso implícitamente) en el cuerpo del constructor antes de asignarse definitivamente.
Si el constructor de instancia de estructura especifica un inicializador de constructor, ese inicializador se considera una asignación definitiva a esto que se produce antes del cuerpo del constructor. Por lo tanto, el propio cuerpo no tiene requisitos de inicialización.
Ejemplo: considere la implementación del constructor de instancia siguiente:
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 } }
No se puede llamar a ningún miembro de función de instancia (incluidos los descriptores de acceso set para las propiedades
X
yY
) hasta que se hayan asignado definitivamente todos los campos de la estructura que se construye. Sin embargo, tenga en cuenta que, siPoint
fuera una clase en lugar de una estructura, se permitiría la implementación del constructor de instancia. Hay una excepción a esto y eso implica las propiedades implementadas automáticamente (§15.7.4). Las reglas de asignación definitivas (§12.21.2) excluyen específicamente la asignación a una propiedad automática de un tipo de estructura dentro de un constructor de instancia de ese tipo de estructura: dicha asignación se considera una asignación definitiva del campo de respaldo oculto de la propiedad automática. Por lo tanto, se permite lo siguiente: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 } }
ejemplo final]
16.4.10 Constructores estáticos
Los constructores estáticos para estructuras siguen la mayoría de las mismas reglas que para las clases. La ejecución de un constructor estático para un tipo de estructura se desencadena mediante el primero de los siguientes eventos que se producirán dentro de un dominio de aplicación:
- Se hace referencia a un miembro estático del tipo de estructura.
- Se llama a un constructor declarado explícitamente del tipo de estructura.
Nota: La creación de valores predeterminados (§16.4.5) de tipos de estructura no desencadena el constructor estático. (Un ejemplo de esto es el valor inicial de los elementos de una matriz). nota final
16.4.11 Propiedades implementadas automáticamente
Las propiedades implementadas automáticamente (§15.7.4) usan campos de respaldo ocultos, que solo son accesibles para los descriptores de acceso de propiedad.
Nota: Esta restricción de acceso significa que los constructores de estructuras que contienen propiedades implementadas automáticamente a menudo necesitan un inicializador de constructor explícito donde, de lo contrario, no necesitarían uno, para satisfacer el requisito de que se asignen definitivamente todos los campos antes de que se invoque a cualquier miembro de función o el constructor devuelva. nota final
16.4.12 Restricción de contexto seguro
16.4.12.1 General
En tiempo de compilación, cada expresión está asociada a un contexto en el que se puede acceder a esa instancia y a todos sus campos de forma segura, su contexto seguro. El contexto seguro es un contexto, que incluye una expresión, a la que es seguro que el valor se escape.
Cualquier expresión cuyo tipo de tiempo de compilación no sea una estructura ref tiene un contexto seguro del contexto del autor de la llamada.
Una default
expresión, para cualquier tipo, tiene un contexto seguro del contexto de llamada.
Para cualquier expresión no predeterminada cuyo tipo de tiempo de compilación sea un struct ref tiene un contexto seguro definido por las secciones siguientes.
Los registros de contexto seguro en los que se puede copiar un valor. Dada una asignación de una expresión E1
con un contexto S1
seguro , a una expresión E2
con contexto S2
seguro , se produce un error si S2
es un contexto más amplio que S1
.
Hay tres valores de contexto seguro diferentes, los mismos que los valores ref-safe-context definidos para las variables de referencia (§9.7.2): declaration-block, function-member y caller-context. El contexto seguro de una expresión restringe su uso de la siguiente manera:
- Para una instrucción
return e1
return , el contexto seguro de debe ser contexto del autor dee1
la llamada. - Para una asignación
e1 = e2
, el contexto seguro dee2
debe ser al menos tan amplio como contexto seguro dee1
.
Para una invocación de método si hay un ref
argumento o out
de un ref struct
tipo (incluido el receptor a menos que el tipo sea readonly
), con contexto S1
seguro , no es posible que ningún argumento (incluido el receptor) tenga un contexto seguro más estrecho que S1
.
16.4.12.2 Contexto seguro de parámetros
Un parámetro de un tipo de estructura ref, incluido el this
parámetro de un método de instancia, tiene un contexto seguro del contexto del autor de la llamada.
16.4.12.3 Contexto seguro de variables locales
Una variable local de un tipo de estructura ref tiene un contexto seguro como se indica a continuación:
- Si la variable es una variable de iteración de un
foreach
bucle, el contexto seguro de la variable es el mismo que el contexto seguro de laforeach
expresión del bucle. - De lo contrario, si la declaración de la variable tiene un inicializador, el contexto seguro de la variable es el mismo que el contexto seguro de ese inicializador.
- De lo contrario, la variable no se inicializa en el punto de declaración y tiene un contexto seguro del contexto de llamada.
16.4.12.4 Contexto seguro del campo
Una referencia a un campo e.F
, donde el tipo de F
es un tipo de estructura ref, tiene un contexto seguro que es el mismo que el contexto seguro de e
.
16.4.12.5 Operadores
La aplicación de un operador definido por el usuario se trata como una invocación de método (§16.4.12.6).
Para un operador que produce un valor, como e1 + e2
o c ? e1 : e2
, el contexto seguro del resultado es el contexto más estrecho entre los contextos seguros de los operandos del operador. Como consecuencia, para un operador unario que produce un valor, como +e
, el contexto seguro del resultado es el contexto seguro del operando.
Nota: El primer operando de un operador condicional es ,
bool
por lo que su contexto seguro es el contexto del autor de la llamada. Sigue que el contexto seguro resultante es el contexto seguro más estrecho del segundo y tercer operando. nota final
16.4.12.6 Invocación de método y propiedad
Un valor resultante de una invocación e1.M(e2, ...)
de método o invocación e.P
de propiedad tiene un contexto seguro del menor de los siguientes contextos:
- contexto del autor de la llamada.
- Contexto seguro de todas las expresiones de argumento (incluido el receptor).
Una invocación de propiedad (ya sea get
o set
) se trata como una invocación de método del método subyacente mediante las reglas anteriores.
16.4.12.7 stackalloc
El resultado de una expresión stackalloc tiene un contexto seguro de miembro de función.
16.4.12.8 Invocaciones del constructor
Una new
expresión que invoca a un constructor cumple las mismas reglas que una invocación de método que se considera que devuelve el tipo que se va a construir.
Además, el contexto seguro es el más pequeño de los contextos seguros de todos los argumentos y operandos de todas las expresiones de inicializador de objeto, recursivamente, si hay algún inicializador presente.
Nota: Estas reglas se basan en
Span<T>
no tener un constructor de la forma siguiente:public Span<T>(ref T p)
Este constructor hace que las instancias de
Span<T>
se usen como campos indistinguibles de unref
campo. Las reglas de seguridad descritas en este documento dependen deref
campos que no sean una construcción válida en C# o .NET. nota final
ECMA C# draft specification