Eventos
17 de mar., 21 - 21 de mar., 10
Junte-se à série de encontros para criar soluções de IA escaláveis com base em casos de uso do mundo real com outros desenvolvedores e especialistas.
Registrar agoraNão há mais suporte para esse navegador.
Atualize o Microsoft Edge para aproveitar os recursos, o suporte técnico e as atualizações de segurança mais recentes.
Observação
Este artigo é uma especificação de recurso. A especificação serve como o documento de design para o recurso. Ela inclui alterações de especificação propostas, juntamente com as informações necessárias durante o design e o desenvolvimento do recurso. Esses artigos são publicados até que as alterações de especificação propostas sejam finalizadas e incorporadas na especificação ECMA atual.
Pode haver algumas divergências entre a especificação do recurso e a implementação concluída. Essas diferenças são capturadas nas notas pertinentes da reunião de design de idioma (LDM).
Você pode saber mais sobre o processo de adoção de speclets de recursos no padrão de linguagem C# no artigo sobre as especificações de .
Problema do especialista: https://github.com/dotnet/csharplang/issues/6065
Essa é uma revisão do recurso inicial de inteiros nativos (especificação), onde os tipos nint
/nuint
eram distintos dos tipos subjacentes System.IntPtr
/System.UIntPtr
.
Em suma, agora tratamos nint
/nuint
como alias simples dos tipos System.IntPtr
/System.UIntPtr
, assim como fazemos para int
em relação a System.Int32
. O sinalizador de recurso em tempo de execução System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr
dispara esse novo comportamento.
O C# fornece um conjunto de tipos de struct
predefinidos chamados de tipos simples. Os tipos simples são identificados por meio de palavras-chave, mas essas palavras-chave são meramente aliases para tipos struct
predefinidos no namespace System
, conforme descrito na tabela a seguir.
Palavra-chave | Tipo com alias |
---|---|
sbyte |
System.SByte |
byte |
System.Byte |
short |
System.Int16 |
ushort |
System.UInt16 |
int |
System.Int32 |
uint |
System.UInt32 |
nint |
System.IntPtr |
nuint |
System.UIntPtr |
long |
System.Int64 |
ulong |
System.UInt64 |
char |
System.Char |
float |
System.Single |
double |
System.Double |
bool |
System.Boolean |
decimal |
System.Decimal |
[...]
O C# dá suporte a onze tipos integrais: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
e char
. [...]
Em outras palavras, um unmanaged_type é um dos seguintes:
sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
, double
, decimal
, ou bool
.As conversões numéricas implícitas são:
sbyte
para short
, int
, nint
, long
, float
, double
ou decimal
.byte
para short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, float
, double
ou decimal
.short
para int
, nint
, long
, float
, double
ou decimal
.ushort
para int
, uint
, nint
, nuint
, long
, ulong
, float
, double
ou decimal
.int
para nint
, long
, float
, double
ou decimal
.uint
para nuint
, long
, ulong
, float
, double
ou decimal
.nint
para long
, float
, double
ou decimal
.nuint
para ulong
, float
, double
ou decimal
.long
para float
, double
ou decimal
.ulong
para float
, double
ou decimal
.char
para ushort
, int
, uint
, nint
, nuint
, long
, ulong
, float
, double
ou decimal
.float
para double
.[...]
Uma conversão de expressão constante implícita permite as conversões a seguir:
int
pode ser convertida no tipo type sbyte
, byte
, short
, ushort
, uint
, nint
, nuint
ou ulong
, desde que o valor da constant_expression esteja dentro do intervalo do tipo de destino.
[...]As conversões numéricas explícitas são as conversões de uma numeric_type para outra numeric_type para a qual ainda não existe uma conversão numérica implícita:
sbyte
para byte
, ushort
, uint
, nuint
, ulong
ou char
.byte
para sbyte
ou char
.short
para sbyte
, byte
, ushort
, uint
, nuint
, ulong
ou char
.ushort
para sbyte
, byte
, short
ou char
.int
para sbyte
, byte
, short
, ushort
, uint
, nuint
, ulong
ou char
.uint
para sbyte
, byte
, short
, ushort
, int
, nint
ou char
.long
para sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, ulong
ou char
.nint
para sbyte
, byte
, short
, ushort
, int
, uint
, nuint
, ulong
ou char
.nuint
para sbyte
, byte
, short
, ushort
, int
, uint
, nint
, long
ou char
.ulong
para sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
ou char
.char
para sbyte
, byte
ou short
.float
para sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
ou decimal
.double
para sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
ou decimal
.decimal
para sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
ou double
.[...]
As conversões de enumeração explícitas são:
sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
, double
ou decimal
a qualquer enum_type.sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
, double
ou decimal
.Considerando dois tipos T₁
e T₂
, T₁
é um destino de conversão melhor do que T₂
se uma das seguintes condições for atendida:
T₁
para T₂
e não existe nenhuma conversão implícita de T₂
para T₁
T₁
é Task<S₁>
, T₂
é Task<S₂>
e S₁
é um destino de conversão melhor do que S₂
T₁
é S₁
ou S₁?
em que S₁
é um tipo integral assinado e T₂
é S₂
ou S₂?
em que S₂
é um tipo integral sem sinal. Especificamente: [...][...] O número de expressões no argument_list deve ser igual à classificação de array_type, e cada expressão deve ser do tipo int
, uint
, nint
, nuint
, long
, ou ulong,
ou deve ser implicitamente conversível para um ou mais desses tipos.
[...] O número de expressões no argument_list deve ser igual à classificação de array_type, e cada expressão deve ser do tipo int
, uint
, nint
, nuint
, long
, ou ulong,
ou deve ser implicitamente conversível para um ou mais desses tipos.
[...] O processamento em tempo de execução de um acesso de matriz do formulário P[A]
, em que P
é um primary_no_array_creation_expression de um array_type e A
é um argument_list, consiste nas seguintes etapas: [...]
int
, uint
, nint
, nuint
, long
, ulong
. O primeiro tipo nessa lista para o qual existe uma conversão implícita é escolhido. [...]A resolução de sobrecarga de operador unário é aplicada para selecionar uma implementação de operador específica. Os operadores predefinidos ++
e --
existem para os seguintes tipos: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
,long
, ulong
, char
, float
, double
, decimal
e qualquer tipo de enumeração.
Os operadores de adição de unários predefinidos são:
...
nint operator +(nint x);
nuint operator +(nuint x);
Os operadores de subtração de unários predefinidos são:
Negação de inteiro:
...
nint operator –(nint x);
Os operadores predefinidos ++
e --
existem para os seguintes tipos: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
, double
, decimal
e qualquer tipo de enumeração.
Além disso, um default_value_expression será uma expressão constante se o tipo for um dos seguintes tipos de valor: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
, double
, decimal
, bool,
ou qualquer tipo de enumeração.
Os operadores de complemento bit a bit predefinidos são:
...
nint operator ~(nint x);
nuint operator ~(nuint x);
Os operadores predefinidos ++
e --
existem para os seguintes tipos: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
, double
, decimal
e qualquer tipo de enumeração.
Os operadores de multiplicação predefinidos estão listados abaixo. Todos os operadores computam o produto de x
e y
.
Multiplicação de inteiros
...
nint operator *(nint x, nint y);
nuint operator *(nuint x, nuint y);
Os operadores de divisão predefinidos estão listados abaixo. Todos os operadores computam o quociente de x
e y
.
Divisão de inteiros:
...
nint operator /(nint x, nint y);
nuint operator /(nuint x, nuint y);
Os operadores restantes predefinidos estão listados abaixo. Todos os operadores computam o restante da divisão entre x
e y
.
Resto inteiro:
...
nint operator %(nint x, nint y);
nuint operator %(nuint x, nuint y);
Adição de inteiros:
...
nint operator +(nint x, nint y);
nuint operator +(nuint x, nuint y);
Subtração de inteiros
...
nint operator –(nint x, nint y);
nuint operator –(nuint x, nuint y);
Os operadores de deslocamento predefinidos estão listados abaixo.
Deslocar à esquerda:
...
nint operator <<(nint x, int count);
nuint operator <<(nuint x, int count);
Deslocar à direita:
...
nint operator >>(nint x, int count);
nuint operator >>(nuint x, int count);
O operador >>
desloca x
para a direita por um número de bits calculado conforme descrito abaixo.
Quando x
é do tipo int
, nint
long
, os bits de ordem baixa de x
são descartados, os bits restantes são deslocados para a direita e as posições de bits vazias de ordem alta são definidas como zero se x
não for negativo e definido como um se x
for negativo.
Quando x
é do tipo uint
, nuint
ou ulong
os bits de ordem baixa de x
são descartados, os bits restantes são deslocados para a direita e as posições de bits vazias de ordem alta são definidas como zero.
Deslocamento para a direita sem sinal:
...
nint operator >>>(nint x, int count);
nuint operator >>>(nuint x, int count);
Para os operadores predefinidos, o número de bits a serem deslocados é computado da seguinte maneira: [...]
x
é nint
ou nuint
, a contagem de deslocamento é fornecida pelos cinco bits de ordem baixa de count
em uma plataforma de 32 bits ou pelos seis bits de ordem baixa de count
em uma plataforma de 64 bits.Os operadores de comparação de inteiro predefinidos são:
...
bool operator ==(nint x, nint y);
bool operator ==(nuint x, nuint y);
bool operator !=(nint x, nint y);
bool operator !=(nuint x, nuint y);
bool operator <(nint x, nint y);
bool operator <(nuint x, nuint y);
bool operator >(nint x, nint y);
bool operator >(nuint x, nuint y);
bool operator <=(nint x, nint y);
bool operator <=(nuint x, nuint y);
bool operator >=(nint x, nint y);
bool operator >=(nuint x, nuint y);
Os operadores lógicos inteiros predefinidos são:
...
nint operator &(nint x, nint y);
nuint operator &(nuint x, nuint y);
nint operator |(nint x, nint y);
nuint operator |(nuint x, nuint y);
nint operator ^(nint x, nint y);
nuint operator ^(nuint x, nuint y);
Uma expressão constante pode ser um tipo de valor ou um tipo de referência. Se uma expressão constante for um tipo de valor, deverá ser um dos seguintes tipos: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
, double
, decimal
, bool,
ou qualquer tipo de enumeração.
[...]
Uma conversão de expressão constante implícita (§10.2.11) permite que uma expressão constante do tipo int
seja convertida em sbyte
, byte
, short
, ushort
, uint
, nint
, nuint
, ou ulong
, desde que o valor da expressão constante esteja dentro do intervalo do tipo de destino.
Os elementos de matriz são acessados usando expressões element_access do formulário A[I₁, I₂, ..., Iₓ]
, em que A
é uma expressão de um tipo de matriz e cada Iₑ
é uma expressão do tipo int
, uint
, nint
, nuint
,long
, ulong
ou pode ser convertido implicitamente em um ou mais desses tipos. O resultado de um acesso de elemento de matriz é uma variável, ou seja, o elemento de matriz selecionado pelos índices.
[...]
Além disso, em um contexto não seguro, o conjunto de conversões explícitas disponíveis é estendido para que inclua as seguintes conversões explícitas de ponteiro:
sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
,long
ou ulong
a qualquer pointer_type.sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
,long
ou ulong
.[...] Em um acesso de elemento de ponteiro do formulário P[E]
, P
deve ser uma expressão de um tipo de ponteiro que não seja void*
e E
deve ser uma expressão que pode ser convertida implicitamente em int
, uint
, nint
, nuint
,long
ou ulong
.
Em um contexto não seguro, o operador +
e o operador –
podem ser aplicados a valores de todos os tipos de ponteiro, exceto void*
. Portanto, para cada tipo de ponteiro T*
, os seguintes operadores são definidos implicitamente:
[...]
T* operator +(T* x, nint y);
T* operator +(T* x, nuint y);
T* operator +(nint x, T* y);
T* operator +(nuint x, T* y);
T* operator -(T* x, nint y);
T* operator -(T* x, nuint y);
Dada uma expressão P
de um tipo de ponteiro T*
e uma expressão N
do tipo int
, uint
, nint
, nuint
, long
ou ulong
, as expressões P + N
e N + P
computam o valor do ponteiro do tipo T*
que resulta da adição de N * sizeof(T)
ao endereço fornecido pelo P
. Da mesma forma, a expressão P – N
calcula o valor do ponteiro do tipo T*
que resulta da subtração de N * sizeof(T)
do endereço fornecido por P
.
Um dos principais impactos desse design é que System.IntPtr
e System.UIntPtr
ganham alguns operadores embutidos (conversões, unários e binários).
Eles incluem os operadores checked
, o que significa que os seguintes operadores nesses tipos agora lançarão uma exceção ao ocorrer um estouro:
IntPtr + int
IntPtr - int
IntPtr -> int
long -> IntPtr
void* -> IntPtr
Esse design significa que nint
e nuint
podem simplesmente ser emitidos como System.IntPtr
e System.UIntPtr
, sem usar System.Runtime.CompilerServices.NativeIntegerAttribute
.
Da mesma forma, ao carregar metadados, NativeIntegerAttribute
pode ser ignorado.
Comentários do C# feature specifications
O C# feature specifications é um projeto código aberto. Selecione um link para fornecer comentários:
Eventos
17 de mar., 21 - 21 de mar., 10
Junte-se à série de encontros para criar soluções de IA escaláveis com base em casos de uso do mundo real com outros desenvolvedores e especialistas.
Registrar agora