Como converter um decimal para um int em c #?

227

Como converter um decimal para um int?

Rob Hruska
fonte
11
Seria útil saber se você queria arredondar para o int mais próximo ou simplesmente colocar os números depois do decimal (ou seja: sempre arredondado para baixo)
Dinah
128
Sinceramente, não vejo sentido em fazer uma votação negativa de perguntas genuínas. Sim, a resposta poderia ser encontrada no Google, mas isso não melhoraria apenas a qualidade do site se as pessoas parassem de fechar cada segunda pergunta? não é como esta questão é spam ou qualquer coisa, e eu tenho certeza que seria útil para muitos de recém-chegado para c #
jay_t55

Respostas:

268

Use a Convert.ToInt32partir mscorlibde

decimal value = 3.14m;
int n = Convert.ToInt32(value);

Veja MSDN . Você também pode usar Decimal.ToInt32. Mais uma vez, consulte MSDN . Finalmente, você pode fazer um elenco direto como em

decimal value = 3.14m;
int n = (int) value;

que usa o operador de conversão explícito. Veja MSDN .

Jason
fonte
10
Cuidado: o Convert possui um comportamento surpreendente para determinadas conversões ( nullvs. 0vs. ""). Eu recomendo não usar Convert a menos que você realmente precisa sua flexibilidade (ou seja, em cenários de tipagem dinâmica)
Eamon Nerbonne
1
-1, pois isso não funcionará para valores como decimal.MaxValue e decimal.MinValue e resulta em um OverflowException. Acredito que @Will fornece uma resposta melhor aqui stackoverflow.com/a/501165/39532
mezoid
8
Tenha cuidado, porque Convert.ToInt32e Decimal.ToInt32se comportam de forma diferente. Do MSDN: Decimal.ToInt32- O valor de retorno é a parte integrante do valor decimal; dígitos fracionários são truncados . Convert.ToInt32- Valor de retorno arredondado para o número inteiro assinado de 32 bits mais próximo. Se o valor estiver na metade do caminho entre dois números inteiros, o número par será retornado; isto é, 4,5 é convertido em 4 e 5.5 é convertido para 6.
vezucci
67

Você não pode.

Bem, é claro que você poderia , no entanto, um int (System.Int32) não é grande o suficiente para armazenar todos os valores decimais possíveis.

Isso significa que, se você converter um decimal maior que int.MaxValue, você excederá o limite e se o decimal for menor que int.MinValue, ele ficará insuficiente.

O que acontece quando você está sobrecarregado? Uma de duas coisas. Se sua construção estiver desmarcada (ou seja, o CLR não se importa se você o fizer), seu aplicativo continuará após o valor exceder / exceder o fluxo, mas o valor no int não será o que você esperava. Isso pode levar a erros intermitentes e pode ser difícil de corrigir. Você terminará seu aplicativo em um estado desconhecido, o que pode resultar em seu aplicativo corrompendo quaisquer dados importantes em que ele esteja trabalhando. Não é bom.

Se sua montagem estiver marcada (propriedades-> compilar-> avançado-> verificar se há aritmética de estouro / estouro ou opção de compilador / marcada), seu código lançará uma exceção quando ocorrer um estouro / estouro. Provavelmente é melhor do que não; no entanto, o padrão para montagens não é verificar se há excesso / vazão.

A verdadeira questão é "o que você está tentando fazer?" Sem conhecer seus requisitos, ninguém pode lhe dizer o que você deve fazer neste caso, além do óbvio: NÃO O FAÇA.

Se você NÃO se importa especificamente, as respostas aqui são válidas. No entanto, você deve comunicar seu entendimento de que um estouro pode ocorrer e que isso não importa, envolvendo seu código de conversão em um bloco não verificado

unchecked
{
  // do your conversions that may underflow/overflow here
}

Dessa forma, as pessoas que estão atrás de você entendem que você não se importa e, no futuro, alguém alterar suas compilações para / verificadas, seu código não será interrompido inesperadamente.

Se tudo o que você deseja fazer é soltar a parte fracionária do número, deixando a parte integral, você pode usar Math.Truncate.

decimal actual = 10.5M;
decimal expected = 10M;
Assert.AreEqual(expected, Math.Truncate(actual));

fonte
3
Embora eu suspeite que eles sejam a mesma coisa se a entrada for decimal, me sinto mais confortável usando Decimal.Truncate do que Math.Truncate, pois o último também aceita dobras e, portanto, pode ser entendido como capaz de truncar números pares que não são a base 10, ao contrário de Decimal.Truncate, que é um verdadeiro truncamento de um número base 10.
24710 Brian Brian
7
Contextos não verificados não se aplicam a decimais; operações decimais lançam OverflowExceptions independentemente.
Dave
46
int i = (int)d;

lhe dará o número arredondado para baixo.

Se você quiser arredondar para o número par mais próximo (por exemplo,> 0,5 arredondará para cima), poderá usar

int i = (int)Math.Round(d, MidpointRounding.ToEven);

Em geral, você pode converter entre todos os tipos numéricos em C #. Se não houver informações que serão perdidas durante o elenco, você poderá fazê-las implicitamente:

int i = 10;
decimal d = i;

embora você ainda possa fazê-lo explicitamente se desejar:

int i = 10;
decimal d = (decimal)i;

No entanto, se você estiver perdendo informações através do elenco, deve fazê-lo explicitamente (para mostrar que está ciente de que pode estar perdendo informações):

decimal d = 10.5M;
int i = (int)d;

Aqui você está perdendo o ".5". Isso pode ser bom, mas você deve ser explícito e fazer uma conversão explícita para mostrar que sabe que pode estar perdendo as informações.

ICR
fonte
1
Na verdade, você deseja que MidpointRounding.AwayFromZero se você quiser que * * seja sempre arredondado com base na minha experiência de experimentar o código acima, analisando exemplos de saída aqui: msdn.microsoft.com/en-us/library/…
Elijah Lofgren
@ElijahLofgren Depende um pouco: se você está fazendo estatísticas, ToEvendeve evitar desvios estatísticos. Se você, no entanto, opera com itens ou dinheiro a pagar, AwayFromZeroparece ser a escolha certa.
mbx
22
decimal d = 2;
int i = (int) d;

Isso deve funcionar muito bem.

luiscubal
fonte
Cuidado, com uma conversão explícita, as informações podem ser perdidas.
Fedro
21
Ao converter de decimal para int, as informações quase sempre são perdidas, mas acredito que esse é o ponto.
Dinah
8

System.Decimalimplementa a IConvertableinterface, que possui um ToInt32()membro.

A chamada System.Decimal.ToInt32()funciona para você?

Andy
fonte
2
Na documentação : "Esta API suporta a infraestrutura do .NET Framework e não se destina a ser usada diretamente no seu código". Por que não usar Convert.ToInt32?
H.Wolper
7

Um bom truque para o arredondamento rápido é adicionar 0,5 antes de converter o decimal em int.

decimal d = 10.1m;
d += .5m;
int i = (int)d;

Ainda sai i=10, mas

decimal d = 10.5m;
d += .5m;
int i = (int)d;

Arredondaria para que i=11.

DeadlyBrad42
fonte
5
Por que se preocupar em fazer isso quando há Math.Floor e Math.Ceiling?
Badaró
Na época, eu era relativamente novo em C # e, por algum motivo, não sabia que essas funções existiam. Na verdade, é um truque que aprendi no C / C ++, onde obviamente era mais útil.
DeadlyBrad42 26/09/09
1
E se o valor decimal fosse, por exemplo, -9,3?
precisa
6

Prefiro usar Math.Round , Math.Floor , Math.Ceiling ou Math.Truncate para definir explicitamente o modo de arredondamento conforme apropriado.

Observe que todos eles retornam Decimal também - como o Decimal possui um intervalo maior de valores que um Int32, você ainda precisará converter (e verificar se há estouro / estouro).

 checked {
   int i = (int)Math.Floor(d);
 }
Mark Brackett
fonte
6

decimal d = 5.5;

int i = decimal.ToInt32(d);// you will get i = 5

ref: texto do link

axel22
fonte
6

Arredondando um decimal para o número inteiro mais próximo

decimal a ;
int b = (int)(a + 0.5m);

quando a = 49.9entãob = 50

quando a = 49.5entãob = 50

quando a = 49.4, então b = 49etc.

sleepwalkerfx
fonte
0

Acho que o operador de conversão não funciona se você tiver um decimal em caixa (ou seja, um valor decimal dentro de um tipo de objeto). Convert.ToInt32 (decimal como objeto) funciona bem nesse caso.

Essa situação surge ao recuperar valores de IDENTITY / AUTONUMBER do banco de dados:

SqlCommand foo = new SqlCommand("INSERT INTO...; SELECT SCOPE_IDENTITY()", conn);
int ID = Convert.ToInt32(foo.ExecuteScalar());  // works
int ID = (int)foo.ExecuteScalar();              // throws InvalidCastException

Consulte 4.3.2 Conversões de unboxing

Timbó
fonte
2
Adicionando mais para referência: isso é porque você pode unbox apenas para o mesmo tipo de original. Aqui SELECT SCOPE_IDENTITY()retorna numeric(38, 0)que é traduzido decimalpelo .NET. foo.ExecuteScalar()retorna uma decimalcaixa como a objectqual não pode ser convertida diretamente para uma int. (int)(decimal)foo.ExecuteScalar()ou Convert.ToInt32(foo.ExecuteScalar())iria funcionar.
Rageit # 9/14
0

Nenhuma resposta parece lidar com a OverflowException / UnderflowException que vem da tentativa de converter um decimal que está fora do intervalo de int.

int intValue = (int)Math.Max(int.MinValue, Math.Min(int.MaxValue, decimalValue));

Esta solução retornará o valor int máximo ou mínimo possível se o valor decimal estiver fora do intervalo int. Você pode adicionar alguns arredondamentos com Math.Round, Math.Ceiling ou Math.Floor para quando o valor estiver dentro do intervalo int.

Kapten-N
fonte