Qual é o til (~) na definição enum?

Estou sempre surpreso que, mesmo depois de usar C # por todo esse tempo, ainda consigo encontrar coisas que eu não sabia …

Eu tentei pesquisar na internet para isso, mas usando o “~” em uma pesquisa não está funcionando para mim tão bem e eu não encontrei nada no MSDN também (para não dizer que não está lá)

Eu vi esse trecho de código recentemente, o que o til (~) significa?

///  /// Enumerates the ways a customer may purchase goods. ///  [Flags] public enum PurchaseMethod { All = ~0, None = 0, Cash = 1, Check = 2, CreditCard = 4 } 

Fiquei um pouco surpreso ao ver isso, então eu tentei compilá-lo, e funcionou … mas eu ainda não sei o que isso significa / faz. Qualquer ajuda??

é o operador de complemento unário – ele inverte os bits de seu operando.

 ~0 = 0xFFFFFFFF = -1 

em aritmética de complemento de dois, ~x == -x-1

O operador ~ pode ser encontrado em praticamente qualquer linguagem que tenha emprestado a syntax de C, incluindo Objective-C / C ++ / C # / Java / Javascript.

Eu pensaria que:

 [Flags] public enum PurchaseMethod { None = 0, Cash = 1, Check = 2, CreditCard = 4, All = Cash | Check | CreditCard } 

Seria um pouco mais claro.

 public enum PurchaseMethod { All = ~0, // all bits of All are 1. the ~ operator just inverts bits None = 0, Cash = 1, Check = 2, CreditCard = 4 } 

Por causa de dois complementos em C #, ~0 == -1 , o número em que todos os bits são 1 na representação binária.

É melhor que o

 All = Cash | Check | CreditCard 

solução, porque se você adicionar outro método mais tarde, diga:

 PayPal = 8 , 

você já estará pronto com o til-All, mas tem que mudar o all-line com o outro. Então, é menos propenso a erros depois.

Saudações

Apenas uma nota lateral, quando você usa

 All = Cash | Check | CreditCard 

você tem o benefício adicional que Cash | Check | CreditCard Cash | Check | CreditCard Cash | Check | CreditCard avaliaria All e não outro valor (-1) que não é igual a todos, embora contenha todos os valores. Por exemplo, se você usar três checkboxs de seleção na interface do usuário

 [] Cash [] Check [] CreditCard 

e sum seus valores, e o usuário seleciona todos eles, você veria All no enum resultante.

Para outros que acharam essa questão esclarecedora, tenho um rápido exemplo para compartilhar. O trecho a seguir da implementação de um método de pintura, conforme detalhado nesta documentação do Mono , usa ~ com ótimo efeito:

 PaintCells (clipBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.SelectionBackground); 

Sem o operador ~ , o código provavelmente seria algo como isto:

 PaintCells (clipBounds, DataGridViewPaintParts.Background | DataGridViewPaintParts.Border | DataGridViewPaintParts.ContentBackground | DataGridViewPaintParts.ContentForeground | DataGridViewPaintParts.ErrorIcon | DataGridViewPaintParts.Focus); 

… porque a enumeração se parece com isso:

 public enum DataGridViewPaintParts { None = 0, Background = 1, Border = 2, ContentBackground = 4, ContentForeground = 8, ErrorIcon = 16, Focus = 32, SelectionBackground = 64, All = 127 // which is equal to Background | Border | ... | Focus } 

Observe a semelhança desse enum com a resposta de Sean Bright?

Eu acho que o mais importante para mim é que ~ é o mesmo operador em um enum como em uma linha normal de código.

É um operador de complemento, Aqui está um artigo que eu geralmente me refiro para operadores bit a bit

http://www.blackwasp.co.uk/CSharpLogicalBitwiseOps.aspx

Também msdn usa no seu artigo enums que demonstra que usa melhor

http://msdn.microsoft.com/pt-br/library/cc138362.aspx

A alternativa que eu pessoalmente uso, que faz a mesma coisa que a resposta do @Sean Bright, mas parece melhor para mim, é esta:

 [Flags] public enum PurchaseMethod { None = 0, Cash = 1, Check = 2, CreditCard = 4, PayPal = 8, BitCoin = 16, All = Cash + Check + CreditCard + PayPal + BitCoin } 

Observe como a natureza binária desses números, que são todos potências de dois, faz a seguinte afirmação verdadeira: (a + b + c) == (a | b | c) . E IMHO, + parece melhor.

Eu fiz algumas experiências com o ~ e acho que poderia ter armadilhas. Considere este trecho para LINQPad que mostra que o valor de todos os enum não se comporta como esperado quando todos os valores são ored juntos.

 void Main() { StatusFilterEnum x = StatusFilterEnum.Standard | StatusFilterEnum.Saved; bool isAll = (x & StatusFilterEnum.All) == StatusFilterEnum.All; //isAll is false but the naive user would expect true isAll.Dump(); } [Flags] public enum StatusFilterEnum { Standard =0, Saved =1, All = ~0 } 

Só quero adicionar, se você usar o [Flags] enum, então pode ser mais conveniente usar o operador de deslocamento à esquerda bit a bit, como este:

 [Flags] enum SampleEnum { None = 0, // 0 First = 1 < < 0, // 1b = 1d Second = 1 << 1, // 10b = 2d Third = 1 << 2, // 100b = 4d Fourth = 1 << 3, // 1000b = 8d All = ~0 // 11111111b }