operador sizeof (referencia de C #)
El sizeofoperador devuelve el número de bytes ocupados por
una variable de un tipo determinado. El argumento para el sizeofoperador debe
ser el nombre de un tipo no administrado o un parámetro de tipo que está
restringido a ser un tipo no administrado.
El sizeof operador requiere
un contexto inseguro . Sin embargo, las expresiones presentadas en la siguiente
tabla se evalúan en tiempo de compilación a los valores constantes
correspondientes y no requieren un contexto inseguro:
Expresión |
Valor constante |
sizeof(sbyte) |
1 |
sizeof(byte) |
1 |
sizeof(short) |
2 |
sizeof(ushort) |
2 |
sizeof(int) |
4 |
sizeof(uint) |
4 |
sizeof(long) |
8 |
sizeof(ulong) |
8 |
sizeof(char) |
2 |
sizeof(float) |
4 |
sizeof(double) |
8 |
sizeof(decimal) |
16 |
sizeof(bool) |
1 |
Tampoco es necesario utilizar un contexto inseguro cuando el
operando del sizeofoperador es el nombre de un tipo de enumeración .
El siguiente ejemplo demuestra el uso del sizeofoperador:
using System; public struct Point { public Point(byte tag, double x, double
y) => (Tag, X, Y) = (tag, x, y); public byte Tag { get; } public double X { get; } public double Y { get; } } public class
SizeOfOperator { public static void Main() { Console.WriteLine(sizeof(byte)); // output: 1
Console.WriteLine(sizeof(double));
// output: 8 DisplaySizeOf<Point>(); // output: Size of Point is 24 DisplaySizeOf<decimal>(); // output: Size of System.Decimal is 16 unsafe {
Console.WriteLine(sizeof(Point*));
// output: 8 } } static unsafe void
DisplaySizeOf<T>() where T : unmanaged { Console.WriteLine($"Size of
{typeof(T)} is {sizeof(T)}"); } } |
El sizeofoperador devuelve una cantidad de bytes que serían
asignados por Common Language Runtime en la memoria administrada. Para los
tipos de estructura , ese valor incluye cualquier relleno, como demuestra el
ejemplo anterior. El resultado del sizeofoperador puede diferir del resultado
del método Marshal.SizeOf , que devuelve el tamaño de un tipo en la memoria no
administrada .
using declaración (Referencia de C #)
Proporciona una sintaxis conveniente que
asegura el uso correcto de los objetos IDisposable . A partir de C # 8.0, la using
declaración garantiza el uso correcto de los objetos IAsyncDisposable .
Ejemplo
El
siguiente ejemplo muestra cómo utilizar la using
declaración.
string
manyLines=@"This is line one This is line two Here is line three The penultimate line
is line four This is the final,
fifth line."; using (var reader =
new StringReader(manyLines)) { string? item; do { item = reader.ReadLine(); Console.WriteLine(item); } while(item != null); } |
A partir de C # 8.0, puede usar la siguiente sintaxis
alternativa para la using
declaración
que no requiere llaves:
string
manyLines=@"This is line one This is line two Here is line three The penultimate line
is line four This is the final,
fifth line."; using var reader =
new StringReader(manyLines); string? item; do { item = reader.ReadLine(); Console.WriteLine(item); } while(item !=
null); |
Observaciones
Archivo y Fuente son ejemplos de
tipos administrados que acceden a recursos no administrados (en este caso,
identificadores de archivos y contextos de dispositivos). Hay muchos otros
tipos de recursos no administrados y tipos de bibliotecas de clases que los
encapsulan. Todos estos tipos deben implementar la interfaz IDisposable o
la interfaz IAsyncDisposable .
Cuando
la vida útil de un IDisposable
objeto se limita a un
solo método, debe declararlo y crear una instancia en la using
declaración. La using
instrucción llama al método Dispose en
el objeto de la manera correcta y (cuando lo usa como se mostró anteriormente)
también hace que el objeto mismo salga del alcance tan pronto como se
llame a Dispose . Dentro del using
bloque, el objeto es de solo lectura y no se puede modificar ni
reasignar. Si el objeto se implementa en IAsyncDisposable
lugar de IDisposable
, la using
instrucción llama a DisposeAsync y awaits
devuelve ValueTask . Para
obtener más información sobre IAsyncDisposable , consulte Implementar
un método DisposeAsync .
La using
declaración asegura que se llame
a Dispose (o DisposeAsync ) incluso si ocurre una excepción
dentro del using
bloque. Puede
lograr el mismo resultado colocando el objeto dentro de un try
bloque y luego llamando a Dispose (o DisposeAsync )
en un finally
bloque; de
hecho, así es como using
el compilador traduce la declaración. El
ejemplo de código anterior se expande al siguiente código en tiempo de
compilación (tenga en cuenta las llaves adicionales para crear el alcance
limitado para el objeto):
La declaración de uso
La using
instrucción
obtiene uno o más recursos, ejecuta una instrucción y luego elimina el recurso.
Un recurso es
una clase o estructura que implementa System.IDisposable
, que incluye un solo método sin parámetros llamado Dispose
. El código que
usa un recurso puede llamar Dispose
para indicar que el recurso ya no es necesario. Si Dispose
no se llama, la
eliminación automática eventualmente ocurre como consecuencia de la recolección
de basura.
Si
la forma de resource_acquisition es local_variable_declaration, entonces el
tipo de local_variable_declaration debe ser uno dynamic
o un tipo al que se
pueda convertir implícitamente System.IDisposable
. Si la forma de resource_acquisition es expresión , esta
expresión debe convertirse implícitamente en System.IDisposable
.
Las
variables locales declaradas en una adquisición de recursos son de solo lectura y deben
incluir un inicializador. Se produce un error en tiempo de compilación si
la declaración incrustada intenta modificar estas variables locales (mediante
asignación o los operadores ++
y --
), tomar la dirección
de ellas o pasarlas como parámetros ref
o out
.
Una using
declaración se traduce en tres partes:
adquisición, uso y disposición. El uso del recurso se try
incluye implícitamente en una declaración
que incluye una finally
cláusula. Esta finally
cláusula elimina el
recurso. Si null
se adquiere un recurso,
no Dispose
se realiza ninguna
llamada a ni se lanza ninguna excepción. Si el recurso es de tipo dynamic
, se convierte
dinámicamente a través de una conversión dinámica implícita (conversiones
dinámicas implícitas ) IDisposable
durante la
adquisición para garantizar que la conversión sea exitosa antes del uso y
eliminación.
¿Qué es el NULL en C#?
Este operador, introducido en la especificación de
C# 2.0, es un complemento perfecto para los tipos anulables al facilitar el
tratamiento de valores nulos. Una de las preguntas típicas que se hacen las
personas que están aprendiendo
Disponible en C# 8.0 y versiones posteriores, el operador !
de postfijo unario es el operador que permite valores NULL o supresión de
valores NULL. En un contexto de anotación que admite un valor NULL habilitado,
se usa el operador que permite un valor NULL para declarar que la expresión x
de un tipo de referencia no es null: x!. El operador ! de prefijo unario es el operador
lógico de negación.
El operador que permite un valor NULL no tiene ningún efecto
en tiempo de ejecución. Solo afecta al análisis de flujo estático del
compilador al cambiar el estado NULL de la expresión. En tiempo de ejecución,
la expresión x!
se evalúa en el resultado de la expresión subyacente x
.
Tipos de referencia
que aceptan valores NULL (referencia de C#)
Los tipos de referencia que aceptan valores NULL están
disponibles a partir de C# 8.0, en un código que ha participado en un contexto compatible con valores NULL. Los tipos de
referencia que aceptan valores NULL, las advertencias de análisis estático NULL
y el operador null-forgiving son
características de lenguaje opcionales. Todas están desactivadas de forma
predeterminada. Un contexto que admite valores
NULL se
controla en el nivel de proyecto mediante la configuración de compilación o en
el código que usa pragmas.
En
un contexto compatible con valores NULL:
·
Una variable de un tipo de referencia T
se debe inicializar con un valor distinto de NULL y nunca
puede tener asignado un valor que sea null
.
·
Una variable de un tipo de referencia T?
se puede inicializar con null
o asignarle null
, pero debe
comprobarse con null
antes de
desreferenciarla.
·
Una variable m
de tipo T?
se considera que no es NULL cuando se aplica el operador
null-forgiving, como en m!
.
Las distinciones entre un tipo de referencia que no acepta
valores NULL T
y un tipo de referencia que acepta valores NULL T?
se aplican mediante la interpretación del
compilador de las reglas anteriores. Una variable de tipo T
y una variable de tipo T?
se representan mediante el mismo
tipo .NET. En el ejemplo siguiente se declara una cadena que no acepta
valores NULL y una cadena que acepta valores NULL y luego se usa el operador
null-forgiving para asignar un valor a una cadena que no acepta valores NULL:
virtual (referencia
de C #)
La virtualpalabra clave se usa para modificar un método,
propiedad, indexador o declaración de evento y permitir que se invalide en una
clase derivada. Por ejemplo, este método puede ser reemplazado por cualquier
clase que lo herede:
public virtual
double Area() { return x * y; } |
La implementación de un miembro virtual puede ser cambiada
por un miembro primordial en una clase derivada. Para
obtener más información sobre cómo utilizar la virtual
palabra clave, consulte Control de versiones con la anulación y nuevas palabras clave y Saber cuándo utilizar la anulación y las nuevas palabras clave .
Observaciones
Cuando
se invoca un método virtual, se comprueba el tipo de tiempo de ejecución del
objeto para un miembro primordial. Se llama al miembro predominante en la
clase más derivada, que podría ser el miembro original, si ninguna clase
derivada ha reemplazado al miembro.