Como posso fazer isso de maneira elegante com C # e .NET 3.5 / 4?
Por exemplo, um número pode estar entre 1 e 100.
Eu sei que um simples se seria suficiente; mas a palavra-chave para esta pergunta é elegância. É para o meu projeto de brinquedo, não para produção.
Essas perguntas não eram sobre velocidade, mas sobre a beleza do código. Pare de falar sobre eficiência e coisas do gênero; lembre-se de que você está pregando para o coral.
if
não for "barroco", não conserte.Respostas:
Há muitas opções:
Além disso, confira esta postagem do SO para opções de regex.
fonte
if
declaração. Isso certamente realiza isso ...;)Você quer dizer?
ou
fonte
Apenas para aumentar o ruído aqui, você pode criar um método de extensão:
O que permitiria fazer algo como ...
Dito isto, isso parece uma coisa boba de se fazer quando o cheque em si é apenas uma linha.
fonte
Como outros disseram, use um simples if.
Você deve pensar na encomenda.
por exemplo
é mais fácil de ler do que
fonte
1 <= x <= 100
.=
vez de==
. Isso não ajuda com operadores relacionais sem igualdade - mas é fácil se acostumar a usá-lo de forma consistente.x
é uma chamada de função complexa ou uma expressão Linq demorada. Nesse caso, você faria isso duas vezes, o que não é uma coisa boa. Claro que você deve armazenar o valor em uma variável local temporária, mas há alguns casos (por exemplo, em instruções else-if-) em que você deseja chamar as funções somente após outras if's ou else-ifs falharam. Com variáveis temporárias, você precisa chamá-las de qualquer maneira antes. Um método de extensão (mencionado em outras respostas) é a melhor solução imho nesses casos.No código de produção, eu simplesmente escreveria
Isso é fácil de entender e muito legível.
Aqui está um método inteligente que reduz o número de comparações de dois para um usando um pouco de matemática. A ideia é que um dos dois fatores se torne negativo se o número estiver fora do intervalo e zero se o número for igual a um dos limites:
Se os limites forem inclusivos:
ou
Se os limites são exclusivos:
ou
fonte
1 < x && x < 100
código produtivo simples . É mais fácil de entender.1 < x & x < 100
(sem && curto-circuito) instrui o compilador que ele sempre pode avaliar,x < 100
independentemente do resultado1 < x
. Estranhamente (devido à previsão de ramificação), é mais rápido sempre fazer essa operação simples do que às vezes ignorá-la.Eu proponho isso:
Exemplos:
e, claro, com variáveis:
É fácil de ler (próximo à linguagem humana) e funciona com qualquer tipo comparável (inteiro, duplo, tipos personalizados ...).
Ter código de fácil leitura é importante porque o desenvolvedor não desperdiçará "ciclos cerebrais" para entendê-lo. Em longas sessões de codificação, os ciclos cerebrais desperdiçados tornam o desenvolvedor cansado antes e propenso a erros.
fonte
IsInRange. I'm not that keen on Ben's inclusive boolean as that requires a few more brain cycles. It has the advantage that it can be used in any class that that implements IComparer. This is in my Extensions now along with
LiesWithin /LiesInside. Just can't decide which.
NotOutside iria funcionar, mas eu não gosto condições negativasCom um pouco de abuso do método de extensão, podemos obter a seguinte solução "elegante":
fonte
enum Inclusive
com os valores:Lower
,Upper
,All
. E passar para aIn
função de um parâmetro adicional do tipoenum Inclusive
com valor padrãoInclusive.All
, atualizar oTo
corpo da função de manusearAll
,Lower
,Upper
valores :)Se isso for acidental,
if
basta um simples . Se isso acontecer em muitos lugares, você pode considerar estes dois:Algo como:
fonte
fonte
Usar uma
&&
expressão para juntar duas comparações é simplesmente a maneira mais elegante de fazer isso. Se você tentar usar métodos de extensão sofisticados e coisas desse tipo, terá a questão de incluir o limite superior, o limite inferior ou ambos. Depois de começar a adicionar variáveis adicionais ou alterar os nomes das extensões para indicar o que está incluído, seu código se torna mais longo e difícil de ler (para a grande maioria dos programadores). Além disso, ferramentas como o Resharper o alertarão se sua comparação não fizer sentido (number > 100 && number < 1
), o que não acontecerá se você usar um método ('i.IsBetween (100, 1)').O único outro comentário que eu faria é que, se você estiver verificando entradas com a intenção de lançar uma exceção, considere usar contratos de código:
Isso é mais elegante do que
if(...) throw new Exception(...)
e você pode receber avisos em tempo de compilação se alguém tentar chamar seu método sem garantir que o número esteja dentro dos limites primeiro.fonte
Se você quiser escrever mais código do que um simples se, talvez você possa: Crie um método de extensão chamado IsBetween
...
Termo aditivo:vale a pena notar que, na prática, você raramente "apenas verifica a igualdade" (ou <,>) em uma base de código. (Exceto nas situações mais triviais.) Apenas como exemplo, qualquer programador de jogos usaria categorias como as seguintes em todos os projetos, como uma questão básica. Observe que neste exemplo (acontece) usando uma função (Mathf.Approximately) que é incorporada ao ambiente; na prática, você normalmente precisa desenvolver cuidadosamente seus próprios conceitos sobre o que as comparações significam para representações computacionais de números reais, para o tipo de situação que você está criando. (Nem mencione que, se você estiver fazendo algo como, talvez um controlador, um controlador PID ou algo semelhante, todo o problema se torna central e muito difícil, torna-se a natureza do projeto.
fonte
return (value >= Min && value <= Max);
Porque todas as outras respostas não são inventadas por mim, aqui apenas minha implementação:
Você pode usá-lo assim:
fonte
EDIT: Nova resposta fornecida. Eu estava começando a usar o C # quando escrevi a primeira resposta a essa pergunta e, em retrospectiva, agora percebo que minha "solução" era / é ingênua e ineficiente.
Minha resposta original: eu usaria a versão mais simples:
if(Enumerable.Range(1,100).Contains(intInQuestion)) { ...DoStuff; }
Uma maneira melhor
Como eu não vi nenhuma outra solução que seja mais eficiente (pelo menos de acordo com meus testes), tentarei outra vez.
Maneira nova e melhor que também funciona com intervalos negativos :
Isso pode ser usado com faixas positivas e negativas e o padrão é uma faixa de
1..100 (inclusive) e usa
x
como o número a ser verificado seguido por um intervalo opcional definido pormin
emax
.Adicionando exemplos para uma boa medida
Exemplo 1:
Devoluções:
Exemplo 2: Usando uma lista de entradas aleatórias entre 1 e 150
Devoluções:
Tempo de execução: 0,016 segundo (s)
fonte
Uma nova reviravolta em um antigo favorito:
fonte
Em C, se a eficiência do tempo for crucial e o excesso de números inteiros for quebrado, seria possível
if ((unsigned)(value-min) <= (max-min)) ...
. Se 'max' e 'min' forem variáveis independentes, a subtração extra para (max-min) perderá tempo, mas se essa expressão puder ser pré-computada no tempo de compilação ou se puder ser calculada uma vez no tempo de execução para testar muitos números no mesmo intervalo, a expressão acima pode ser calculada com eficiência, mesmo no caso em que o valor esteja dentro do intervalo (se uma grande fração de valores estiver abaixo do intervalo válido, poderá ser mais rápido usar,if ((value >= min) && (value <= max)) ...
pois sairá mais cedo se valor é menor que min).Antes de usar uma implementação como essa, avalie a máquina de destino de uma pessoa. Em alguns processadores, a expressão em duas partes pode ser mais rápida em todos os casos, pois as duas comparações podem ser feitas independentemente, enquanto no método subtrair e comparar a subtração deve ser concluída antes que a comparação possa ser executada.
fonte
Que tal algo como isso?
com o método de extensão da seguinte forma (testado):
fonte
Eu faria um objeto Range, algo como isto:
Então você o usa desta maneira:
Dessa forma, você pode reutilizá-lo para outro tipo.
fonte
Range
objeto precisa usar oCompareTo
método para comparar itens, não o<
operador.IComparable
e não sobrecarregue o<
operador.Ao verificar se um "Número" está em um intervalo, você precisa ter uma noção clara do que você quer dizer, e o que dois números são iguais? Em geral, você deve agrupar todos os números de ponto flutuante no que é chamado de 'bola epsilon', para isso, escolha um valor pequeno e diga que se dois valores estão tão próximos, eles são a mesma coisa.
Com esses dois auxiliares no lugar e assumindo que, se algum número puder ser convertido em dobro, sem a precisão necessária. Tudo que você precisa agora é uma enumeração e outro método
O outro método segue:
Agora, isso pode ser muito mais do que o que você queria, mas impede que você lide com o arredondamento o tempo todo e tente se lembrar se um valor foi arredondado e em que lugar. Se necessário, você pode estendê-lo facilmente para trabalhar com qualquer epsilon e permitir que ele mude.
fonte
Uso
double numberToBeChecked = 7;
var resultado = numberToBeChecked.IsBetween (100,122);
resultado var = 5.IsBetween (100,120);
resultado var = 8.0.IsBetween (1.2,9.6);
fonte
Se você está preocupado com o comentário de @Daap na resposta aceita e só pode passar o valor uma vez, tente um dos seguintes
ou
fonte
Em relação à elegância, a coisa mais próxima da notação matemática ( a <= x <= b ) melhora ligeiramente a legibilidade:
Para mais ilustrações:
fonte
Eu estava procurando uma maneira elegante de fazê-lo onde os limites pudessem ser alterados (ou seja, não tenho certeza de qual ordem os valores estão).
Isso funcionará apenas em versões mais recentes do C # onde existe o?:
Obviamente, você pode alterar os sinais = para seus propósitos. Também pode ser extravagante com a conversão de tipos. Eu só precisava de um retorno de flutuação dentro dos limites (ou igual a)
fonte
Elegante porque não requer que você determine qual dos dois valores de limite é maior primeiro. Ele também não contém ramificações.
fonte
Eu não sei, mas eu uso este método:
E é assim que posso usá-lo:
fonte
Estes são alguns métodos de extensão que podem ajudar
fonte
Para validar os parâmetros do método, nenhuma das soluções lança ArgumentOutOfRangeException e permite a configuração fácil / adequada de valores mínimos / máximos inclusivos / exclusivos.
Use assim
Acabei de escrever essas belas funções. Ele também tem a vantagem de não ter ramificação (um único se) para valores válidos. A parte mais difícil é criar as mensagens de exceção adequadas.
fonte
Você está procurando
in [1..100]
? Isso é apenas Pascal.fonte
when (number) { in 0..9 -> println("1 digit") in 10..99 -> println("2 digits") in 100..999 -> println("3 digits") }