
C# Zero To Hero — Tipos
Os tipos na linguagem C# são divididos em duas categorias principais: tipos de valor e tipos de referência. Ambos os tipos podem ser genéricos, que usam um ou mais parâmetros de tipo. Os parâmetros de tipo podem designar tipos de valor e tipos de referência.
type: value_type| reference_type| type_parameter| type_unsafe;A categoria final de tipos, ponteiros, está disponível somente em código não seguro. Isso é discutido mais adiante nos tipos de ponteiro.
Os tipos de valor diferem dos tipos de referência em que as variáveis dos tipos de valor contêm diretamente seus dados, enquanto as variáveis dos tipos de referência armazenam referências a seus dados, sendo estes últimos conhecidos como objetos. Com os tipos de referência, é possível que duas variáveis façam referência ao mesmo objeto e, portanto, possível que as operações em uma variável afetem o objeto referenciado pela outra variável. Com tipos de valor, cada variável tem sua própria cópia dos dados e não é possível que as operações em uma afetem a outra.
O sistema de tipos do C# é unificado de forma que um valor de qualquer tipo possa ser tratado como um objeto. Cada tipo em C# deriva direta ou indiretamente do tipo de classe object e sendo esta a última classe base de todos os tipos. Valores de tipos de referência são tratados como objetos simplesmente visualizando os valores como tipo object. Valores de tipos de valor são tratados como objetos através da realização de operações de box e unboxing.
Tipos de valor
Um tipo de valor é um tipo de estrutura ou um tipo de enumeração. C# fornece um conjunto de tipos de estruturas predefinidos chamados tipos simples. Os tipos simples são identificados através de palavras reservadas.
value_type: struct_type | enum_type;struct_type: type_name | simple_type | nullable_type;simple_type: numeric_type | ‘bool’;numeric_type: integral_type| floating_point_type| ‘decimal’;integral_type: ‘sbyte’| ‘byte’| ‘short’| ‘ushort’| ‘int’| ‘uint’| ‘long’| ulong’| ‘char’;floating_point_type: ‘float’| ‘double’;nullable_type: non_nullable_value_type ‘?’;non_nullable_value_type: type;enum_type: type_name;
Ao contrário de uma variável de um tipo de referência, uma variável de um tipo de valor pode conter o valor null apenas se o tipo de valor for um tipo anulável. Para cada tipo de valor não anulável, existe um tipo de valor anulável correspondente que indica o mesmo conjunto de valores mais o valor null.
A atribuição a uma variável de um tipo de valor cria uma cópia do valor que está sendo atribuído. Isso difere da atribuição para uma variável de um tipo de referência, que copia a referência, mas não o objeto identificado pela referência.
O tipo System.ValueType
Todos os tipos de valor herdam implicitamente da classe System.ValueType, que, por sua vez, herda da classe object. Não é possível para qualquer tipo derivar de um tipo de valor, e os tipos de valores são, portanto, implicitamente selados.
Note que System.ValueType não é em si um value_type. Em vez disso, é um class_type do qual todos os value_type’s são automaticamente derivados.
Construtores Padrão
Todos os tipos de valor declaram implicitamente um construtor de instância pública sem parâmetros chamado de construtor padrão. O construtor padrão retorna uma instância inicializada como zero, conhecida como o valor padrão para o tipo de valor:
Para todos os simple_type’s, o valor padrão é o valor produzido por um padrão de bits:
- Por
sbyte,byte,short,ushort,int,uint,long, eulong, o valor padrão é0. - Para
char, o valor padrão é'\x0000'. - Para
float, o valor padrão é0.0f. - Para
double, o valor padrão é0.0d. - Para
decimal, o valor padrão é0.0m. - Para
bool, o valor padrão éfalse.
Para um enum_type ‘E’, o valor padrão é convertido para o tipo ‘E’.
Para um struct_type, o valor padrão é o valor produzido configurando todos os campos de tipo de valor para seu valor padrão e todos os campos de tipo de referência para null.
Para um tipo nullable_type, o valor padrão é uma instância para a qual a propriedade HasValue é false e a propriedade Value é indefinida. O valor padrão também é conhecido como o valor nulo do tipo anulável.
Como qualquer outro construtor de instância, o construtor padrão de um tipo de valor é chamado usando o operador new. Por motivos de eficiência, esse requisito não tem a intenção de realmente fazer com que a implementação gere uma chamada de construtor. No exemplo abaixo, as variáveis i e j são inicializadas com valor igual a zero.
class A
{
void F()
{
int i = 0;
int j = new int();
}
}Como cada tipo de valor implicitamente tem um construtor de instância público sem parâmetros, não é possível que um tipo de estrutura contenha uma declaração explícita de um construtor sem parâmetros. No entanto, um tipo de estrutura pode declarar construtores de instância parametrizados.
Tipos de estruturas
Um tipo de estrutura é um tipo de valor que pode declarar constantes, campos, métodos, propriedades, indexadores, operadores, construtores de instância, construtores estáticos e tipos aninhados. A declaração de tipos de estrutura é descrita nas declarações de Struct.
Tipos simples
C# fornece um conjunto de tipos de estruturas predefinidos chamados tipos simples. Os tipos simples são identificados por meio de palavras reservadas, mas essas palavras reservadas são simplesmente ‘aliases’ para tipos de estruturas predefinidos no namespace System, conforme descrito na tabela abaixo.

Os tipos simples diferem de outros tipos de estruturas na medida em que permitem certas operações adicionais:
- A maioria dos tipos simples permite que valores sejam criados escrevendo literais. Por exemplo,
123é um literal do tipointe'a’é um literal do tipochar. C# não faz provisão para literais de tipos de estruturas em geral, e valores não-padrão de outros tipos de estruturas são sempre criados através de construtores de instância daqueles tipos de struct. - Quando os operandos de uma expressão são todos constantes de tipo simples, é possível que o compilador avalie a expressão em tempo de compilação. Essa expressão é conhecida como expressão constante. Expressões envolvendo operadores definidos por outros tipos de struct não são consideradas expressões constantes.
- Através de declarações
consté possível declarar constantes dos tipos simples. Não é possível ter constantes de outros tipos de estruturas, mas um efeito semelhante é fornecido por camposstatic readonly;. - Conversões envolvendo tipos simples podem participar da avaliação de operadores de conversão definidos por outros tipos de estruturas, mas um operador de conversão definido pelo usuário nunca pode participar da avaliação de outro operador definido pelo usuário.
Tipos integrais
C# suporta nove tipos integrais: sbyte, byte, short, ushort, int, uint, long, ulong, e char. Os tipos integrais possuem os seguintes tamanhos e intervalos de valores:
- O tipo
sbyterepresenta inteiros de 8 bits assinados com valores entre -128 e 127. - O tipo
byterepresenta números inteiros de 8 bits não assinados com valores entre 0 e 255. - O tipo
shortrepresenta inteiros de 16 bits assinados com valores entre -32768 e 32767. - O tipo
ushortrepresenta inteiros de 16 bits não assinados com valores entre 0 e 65535. - O tipo
intrepresenta inteiros de 32 bits assinados com valores entre -2147483648 e 2147483647. - O tipo
uintrepresenta números inteiros de 32 bits não assinados com valores entre 0 e 4294967295. - O tipo
longrepresenta inteiros assinados de 64 bits com valores entre -9223372036854775808 e 9223372036854775807. - O tipo
ulongrepresenta inteiros de 64 bits sem sinal com valores entre 0 e 18446744073709551615. - O tipo
charrepresenta inteiros de 16 bits não assinados com valores entre 0 e 65535. O conjunto de valores possíveis para o tipocharcorresponde ao conjunto de caracteres Unicode. Emborachartenha a mesma representaçãoushort, nem todas as operações permitidas em um tipo são permitidas no outro.
Os operadores unário e binário do tipo integral sempre operam com precisão de 32 bits assinada, precisão de 32 bits não assinada, precisão de 64 bits assinada ou precisão de 64 bits não assinada:
- Para os operadores unários
+e~, o operando é convertido no tipoT, ondeTé o primeiro deint,uint,longeulongque podem representar totalmente todos os valores possíveis do operador. A operação é então executada usando a precisão do tipoTe o tipo do resultado éT. - Para operador unário ‘-’, o operando é convertido no tipo
T, ondeTé o primeiro deintelongque pode representar totalmente todos os valores possíveis do operando. A operação é então executada usando a precisão do tipoTe o tipo do resultado éT. O operador unário ‘-’ não pode ser aplicado a operandos do tipoulong. - Para o binário
+,-,*,/,%,&,^,|,==,!=,>,<,>=, e<=os operadores, os operandos são convertidos para o tipoT, ondeTé a primeira deint,uint,long, eulongque podem representar totalmente todos os valores possíveis de ambos os operandos. A operação é então executada usando a precisão do tipoTe o tipo do resultado éT(ouboolpara os operadores relacionais). Não é permitido que um operando seja do tipolonge o outro seja do tipoulongcom os operadores binários. - Para o operador binário
<<e>>, o operando esquerdo é convertido no tipoT, ondeTé o primeiro deint,uint,long, eulongque pode representar plenamente todos os valores possíveis do operando. A operação é então executada usando a precisão do tipoTe o tipo do resultado éT.
O tipo char é classificado como um tipo integral, mas difere dos outros tipos integrais de duas maneiras:
- Não há conversões implícitas de outros tipos para o tipo
char. Em particular, embora os tipossbyte,byte, eushorttêm gamas de valores que são totalmente representável usando o tipochar, as conversões implícitas a partir desbyte,byteouushortacharnão existem. - Constantes do tipo
chardevem ser escritas como character_literal s ou como integer_literal s em combinação com um cast to tipochar. Por exemplo,(char)10é o mesmo que'\x000A'.
Os operadores checked, unchecked e instruções são utilizados para controlar verificação de estouro para operações e conversões aritméticas do tipo integral. Em um contexto checked, um estouro produz um erro em tempo de compilação ou faz com que um System.OverflowExceptionseja lançado. Em um contexto unchecked, os overflows são ignorados e quaisquer bits de alta ordem que não se encaixam no tipo de destino são descartados.
Tipos de ponto flutuante
C# suporta dois tipos de ponto flutuante: float e double. Os tipos float e double são representados usando os formatos IEEE 754 de precisão simples de 32 bits e IEEE 754 de precisão dupla, que fornecem os seguintes conjuntos de valores:
- Zero positivo e zero negativo. Na maioria das situações, zero positivo e zero negativo se comportam identicamente como o valor simples zero, mas certas operações distinguem entre os dois.
- Infinito positivo e infinito negativo. Infinidades são produzidas por tais operações como dividir um número diferente de zero por zero. Por exemplo,
1.0 / 0.0gera infinito positivo e-1.0 / 0.0gera infinito negativo. - O valor não-numérico, geralmente abreviado NaN. NaNs são produzidos por operações inválidas de ponto flutuante, como dividir zero por zero.
- O conjunto finito de valores diferentes de zero do formulário
s * m * 2^e, ondesé 1 ou -1,meeé determinado pelo tipo de ponto flutuante específico: Parafloat,0 < m < 2^24and-149 <= e <= 104e paradouble,0 < m < 2^53and1075 <= e <= 970. Números de ponto flutuante desnormalizados são considerados valores válidos diferentes de zero.
O tipo float pode representar valores que variam de aproximadamente 1.5 * 10^-45 a 3.4 * 10^38 uma precisão de 7 dígitos.
O tipo double pode representar valores que variam de aproximadamente 5.0 * 10^-324a 1.7 × 10^308 uma precisão de 15 a 16 dígitos.
Se um dos operandos de um operador binário for de um tipo de ponto flutuante, o outro operando deverá ser de um tipo integral ou um tipo de ponto flutuante, e a operação será avaliada da seguinte maneira:
- Se um dos operandos for de um tipo integral, esse operando é convertido para o tipo de ponto flutuante do outro operando.
- Então, se um dos operandos for do tipo
double, o outro operando é convertidodouble, a operação é executada usando pelo menos o intervalo e a precisãodouble, e o tipo do resultado édouble(ouboolpara os operadores relacionais). - Caso contrário, a operação é executada usando pelo menos intervalo e precisão
float, e o tipo do resultado éfloat(ouboolpara os operadores relacionais).
Os operadores de ponto flutuante, incluindo os operadores de atribuição, nunca produzem exceções. Em vez disso, em situações excepcionais, as operações de ponto flutuante produzem zero, infinito ou NaN, conforme descrito abaixo:
- Se o resultado de uma operação de ponto flutuante for muito pequeno para o formato de destino, o resultado da operação se tornará zero ou zero positivo.
- Se o resultado de uma operação de ponto flutuante for muito grande para o formato de destino, o resultado da operação se tornará infinito positivo ou infinito negativo.
- Se uma operação de ponto flutuante for inválida, o resultado da operação se tornará NaN.
- Se um ou ambos os operandos de uma operação de ponto flutuante for NaN, o resultado da operação se tornará NaN.
Operações de ponto flutuante podem ser executadas com maior precisão do que o tipo de resultado da operação. Por exemplo, algumas arquiteturas de hardware suportam um tipo de ponto flutuante “estendido” ou “longo duplo” com maior alcance e precisão que o tipo double e executam implicitamente todas as operações de ponto flutuante usando esse tipo de precisão mais alta. Somente com custo excessivo no desempenho essas arquiteturas de hardware podem executar operações de ponto flutuante com menos precisão e, em vez de exigir uma implementação para perder desempenho e precisão, o C# permite que um tipo de precisão mais alta seja usado para todas as operações de ponto flutuante. Além de fornecer resultados mais precisos, isso raramente tem efeitos mensuráveis. Contudo, em expressões da formax * y / z, onde a multiplicação produz um resultado que está fora do intervalo double, mas a divisão subsequente traz o resultado temporário de volta ao intervalo double, o fato de a expressão ser avaliada em um formato de intervalo maior pode causar um resultado finito em vez de um infinito.
O tipo decimal
O tipo decimal é um tipo de dados de 128 bits adequado para cálculos financeiros e monetários. O tipo decimal pode representar valores que variam de 1.0 * 10^-28aproximadamente 7.9 * 10^2828 a 29 dígitos significativos.
O conjunto finito de valores do tipo decimalé da forma (-1)^s * c * 10^-e, onde o sinal sé 0 ou 1, o coeficiente cé dado por 0 <= *c* < 2^96, e a escala e é tal que 0 <= e <= 28. O tipo decimal não suporta zeros, infinitos ou NaNs assinados. O tipo decimalé representado como um inteiro de 96 bits escalado por uma potência de dez. Para decimais com um valor absoluto menor que 1.0m, o valor é exato para a 28ª casa decimal, mas não mais. Para decimiais com um valor absoluto maior ou igual a 1.0m, o valor é exato para 28 ou 29 dígitos. Ao contrário dos tipos de dados float e double, números fracionários decimais, como 0.1, podem ser representados exatamente na representação decimal. Nas representações floatedouble, esses números são muitas vezes frações infinitas, tornando essas representações mais propensas a erros de arredondamento.
Se um dos operandos de um operador binário é do tipo decimal, então o outro operando deve ser de um tipo integral ou de tipo decimal. Se um operando do tipo integral estiver presente, ele será convertido para decimal antes da operação ser executada.
O resultado de uma operação em valores de tipo decimal é aquele que resultaria do cálculo de um resultado exato (preservando a escala, conforme definido para cada operador) e, em seguida, arredondando para ajustar a representação. Os resultados são arredondados para o valor representável mais próximo e, quando um resultado é igualmente próximo de dois valores representáveis, para o valor que tem um número par na posição de dígito menos significativo (isso é conhecido como "arredondamento do banqueiro"). Um resultado zero sempre tem um sinal de 0 e uma escala de 0.
Se uma operação aritmética decimal produzir um valor menor ou igual a 5 * 10^-29em valor absoluto, o resultado da operação se tornará zero. Se uma operação decimal aritmética produz um resultado que é muito grande para o formato decimal, a System.OverflowExceptioné lançada.
O tipo decimal tem maior precisão, mas menor alcance que os tipos de ponto flutuante. Portanto, as conversões dos tipos de ponto flutuante para decimalproduzem exceções de estouro e as conversões decimal para os tipos de ponto flutuante podem causar perda de precisão. Por esses motivos, não há conversões implícitas entre os tipos de ponto flutuante e decimal, sem cast’s explícitos, não é possível misturar operandos decimal de ponto flutuante na mesma expressão.
O tipo de bool
O tipo bool representa quantidades lógicas booleanas. Os valores possíveis do tipo bool são true e false.
Não há conversões padrão entre bool e outros tipos. Em particular, o tipo bool é distinto e separado dos tipos integrais, e um valor bool não pode ser usado no lugar de um valor integral e vice-versa.
Nas linguagens C e C ++, um valor zero integral ou de ponto flutuante, ou um ponteiro nulo pode ser convertido para o valor booleano false, e um valor integral diferente de zero ou de ponto flutuante, ou um ponteiro não nulo pode ser convertido para o valor booleano true. Em C#, essas conversões são realizadas comparando explicitamente um valor integral ou de ponto flutuante a zero ou comparando explicitamente uma referência de objeto a null.
Tipos de enumeração
Um tipo de enumeração é um tipo distinto com constantes nomeadas. Cada tipo de enumeração tem um tipo subjacente, que deve ser byte, sbyte, short, ushort, int, uint, longou ulong. O conjunto de valores do tipo de enumeração é o mesmo que o conjunto de valores do tipo subjacente. Valores do tipo de enumeração não estão restritos aos valores das constantes nomeadas. Os tipos de enumeração são definidos por meio de declarações de enumeração.
Tipos anuláveis
Um tipo anulável pode representar todos os valores de seu tipo subjacente mais um valor nulo adicional. Um tipo anulável é gravado T?, onde Té o tipo subjacente. Essa sintaxe é uma forma abreviada de System.Nullable<T>e as duas formas podem ser usadas de forma intercambiável.
Um tipo de valor não anulável, ao contrário, é qualquer tipo de valor diferente System.Nullable<T>e sua abreviação T?(para qualquer T), além de qualquer parâmetro de tipo que é restrito a um tipo de valor não anulável (isto é, qualquer parâmetro de tipo com uma restrição struct). O System.Nullable<T>tipo especifica a restrição de tipo de valor para T, o que significa que o tipo subjacente de um tipo anulável pode ser qualquer tipo de valor não anulável. O tipo subjacente de um tipo anulável não pode ser um tipo anulável ou um tipo de referência. Por exemplo, int??e string?são tipos inválidos.
Uma instância de um tipo anulável T? possui duas propriedades públicas de somente leitura:
- Uma propriedade
HasValuedo tipobool - Uma propriedade
Valuedo tipoT
Uma instância para a qual HasValueé verdadeira é considerada não nula. Uma instância não nula contém um valor conhecido e Value retorna esse valor.
Uma instância para a qual HasValue é falso é dita nula. Uma instância nula tem um valor indefinido. A tentativa de ler o Value de uma instância nula faz com que um System.InvalidOperationException seja lançado. O processo de acessar a propriedade Value de uma instância anulável é conhecido como ‘desempacotar ‘.
Além do construtor padrão, todo tipo anulável T?possui um construtor público que aceita um único argumento do tipo T. Dado um valor x de tipo T, uma invocação de construtor do formulário
new T?(x)cria uma instância não nula T? para a qual a Value propriedade é x. O processo de criação de uma instância não nula de um tipo anulável para um determinado valor é referido como quebra automática .
As conversões implícitas estão disponíveis a partir do literal null para T? e a partir Tde T?.
Tipos de referência
Um tipo de referência é um tipo de classe, um tipo de interface, um tipo de matriz ou um tipo de delegado.
reference_type: class_type| interface_type| array_type| delegate_type;class_type: type_name| 'object'| 'dynamic'| 'string';interface_type: type_name;array_type: non_array_type rank_specifier+;non_array_type: type;rank_specifier: '[' dim_separator* ']';dim_separator: ',';delegate_type: type_name;
Um valor de tipo de referência é uma referência a uma instância do tipo, a última conhecida como um objeto. O valor especial null é compatível com todos os tipos de referência e indica a ausência de uma instância.
Tipos de classe
Um tipo de classe define uma estrutura de dados que contém membros de dados (constantes e campos), membros de função (métodos, propriedades, eventos, indexadores, operadores, construtores de instância, destrutores e construtores estáticos) e tipos aninhados. Tipos de classes suportam herança, um mecanismo pelo qual classes derivadas podem estender e especializar classes base. Instâncias de tipos de classes são criadas usando expressões de criação de objetos.
Determinados tipos de classe predefinidos têm um significado especial na linguagem C#, conforme descrito na listagem abaixo.
- System.Object: A classe base final de todos os outros tipos. Veja o tipo de objeto .
- System.String: O tipo de string da linguagem C#. Veja o tipo de string .
- System.ValueType: A classe base de todos os tipos de valor. Consulte o tipo System.ValueType .
- System.Enum: A classe base de todos os tipos de enumeração.
- System.Array: A classe base de todos os tipos de matriz.
- System.Delegate: A classe base de todos os tipos de delegados.
- System.Exception: A classe base de todos os tipos de exceção.
O tipo de objeto
O tipo de classe object é a última classe base de todos os outros tipos. Cada tipo em C# deriva direta ou indiretamente do tipo de classe object.
A palavra-chave object é simplesmente um alias para a classe predefinida System.Object.
O tipo dinâmico
O tipo dynamic, como object, pode referenciar qualquer objeto. Quando os operadores são aplicados a expressões do tipo dynamic, sua resolução é adiada até que o programa seja executado. Assim, se o operador não puder ser legalmente aplicado ao objeto referenciado, nenhum erro será dado durante a compilação. Em vez disso, uma exceção será lançada quando a resolução do operador falhar no tempo de execução.
Sua finalidade é permitir a vinculação dinâmica, descrita em detalhes na vinculação dinâmica.
Dynamic é considerado idêntico ao tipo object exceto nos seguintes aspectos:
- Operações em expressões do tipo dynamic podem ser vinculadas dinamicamente (ligação dinâmica).
- A inferência de tipos preferirá o dynamic ao invés de object se ambos forem candidatos.
Devido a essa equivalência, o seguinte é válido:
- Há uma conversão de identidade implícita entre object e dynamic, e entre tipos construídos que são os mesmos quando substituídos dynamic por object
- Conversões implícitas e explícitas de e para object também se aplicam a e de dynamic.
- Assinaturas de método que são as mesmas ao substituir dynamic por object são consideradas a mesma assinatura
- O tipo dynamic é indistinguível de object em tempo de execução.
- Uma expressão do tipo dynamic é referido como uma expressão dinâmica .
O tipo de string
O tipo string é um tipo de classe lacrado(selado) que herda diretamente de object. Instâncias da classe string representam cadeias de caracteres Unicode.
Valores do tipo string podem ser gravados como literais de string.
A palavra-chave string é simplesmente um alias para a classe predefinida System.String.
Tipos de interface
Uma interface define um contrato. Uma classe ou estrutura que implemente uma interface deve aderir ao seu contrato. Uma interface pode herdar de várias interfaces de base e uma classe ou estrutura pode implementar várias interfaces.
Tipos de matriz
Um array é uma estrutura de dados que contém zero ou mais variáveis que são acessadas através de índices computados. As variáveis contidas em uma matriz, também chamadas de elementos da matriz, são todas do mesmo tipo e esse tipo é chamado de tipo de elemento da matriz.
Tipos de delegado
Um delegado é uma estrutura de dados que se refere a um ou mais métodos. Por exemplo, métodos, também se refere às suas instâncias de objetos correspondentes.
O equivalente mais próximo de um delegado em C ou C ++ é um ponteiro de função, mas enquanto um ponteiro de função pode referenciar apenas funções estáticas, um delegado pode fazer referência a métodos estáticos e de instância. No último caso, o delegado armazena não apenas uma referência ao ponto de entrada do método, mas também uma referência à instância do objeto na qual invocar o método.
Boxe e unboxing
O conceito de boxe e unboxing é central para o sistema de tipos do C#. Ele fornece uma ponte entre value_type s e reference_type s, permitindo que qualquer valor de um value_type seja convertido para o tipo object. Boxing e unboxing permitem uma visão unificada do sistema de tipos, onde um valor de qualquer tipo pode ser tratado como um objeto.
Conversões de boxe
Uma conversão de boxe permite que um value_type seja implicitamente convertido em um reference_type . As seguintes conversões de boxe existem:
- De qualquer value_type para o tipo object.
- De qualquer value_type para o tipo System.ValueType.
- De qualquer non_nullable_value_type para qualquer interface_type implementado pelo value_type .
- De qualquer nullable_type para qualquer interface_type implementado pelo tipo subjacente de nullable_type .
- De qualquer enum_type para o tipo System.Enum.
- De qualquer nullable_type com um enum_type subjacente ao tipo System.Enum.
Observe que uma conversão implícita de um parâmetro de tipo será executada como uma conversão de boxing se, em tempo de execução, ele for convertido de um tipo de valor para um tipo de referência.
Boxe um valor de um non_nullable_value_type consiste em alocar uma instância de objeto e copiar o valor non_nullable_value_type nessa instância.
Boxing um valor de um nullable_type produz uma referência nula se for null o valor ( HasValue é false), ou o resultado de desempacotar(unbox) e encaixar o valor subjacente de outra forma.
O processo real de empacotar um valor de um non_nullable_value_type é melhor explicado imaginando a existência de uma classe genérica de empacotamento(box), que se comporta como se fosse declarada da seguinte forma:
sealed class Box<T>:System.ValueType
{
T value; public Box(T t)
{
value =t;
}
}
O boxe de um valor do tipo T agora consiste em executar a expressão new Box<T>(v) e retornar a instância resultante como um valor do tipo object. Assim, as declarações
int i = 123;
object box = i;conceitualmente correspondem a
int i = 123;
object box = new Box<int>(i);Uma classe de boxe como Box<T>acima, na verdade, não existe e o tipo dinâmico de um valor na caixa não é realmente um tipo de classe. Em vez disso, um valor de tipo T em Box tem o tipo dinâmico T e uma verificação de tipo dinâmico usando o operador ‘is’ pode simplesmente referenciar o tipo T. Por exemplo,
int i = 123;
object box = i;
if (box is int)
{
Console.Write("Box contains an int");
}