web-dev-qa-db-fra.com

Quel est le tilde (~) dans la définition de l'énumération?

Je suis toujours surpris que même après avoir utilisé C # pendant tout ce temps maintenant, j'arrive toujours à trouver des choses que je ne connaissais pas ...

J'ai essayé de chercher sur Internet pour cela, mais l'utilisation du "~" dans une recherche ne fonctionne pas si bien pour moi et je n'ai rien trouvé non plus sur MSDN (pour ne pas dire qu'il n'y est pas)

J'ai récemment vu cet extrait de code, que signifie le tilde (~)?

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

J'étais un peu surpris de le voir alors j'ai essayé de le compiler, et cela a fonctionné ... mais je ne sais toujours pas ce que cela signifie/fait. De l'aide??

143
Hugoware

~ est l'opérateur complémentaire unaire - il retourne les bits de son opérande.

~0 = 0xFFFFFFFF = -1

dans l'arithmétique du complément à deux, ~x == -x-1

l'opérateur ~ peut être trouvé dans pratiquement tous les langages empruntant la syntaxe à C, y compris Objective-C/C++/C #/Java/Javascript.

134
Jimmy

Je pense que:

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

Serait un peu plus clair.

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

En raison de deux compléments en C #, ~0 == -1, le nombre où tous les bits sont 1 dans la représentation binaire.

22

C'est mieux que le

All = Cash | Check | CreditCard

solution, car si vous ajoutez une autre méthode plus tard, dites:

Paypal = 8 ,

vous aurez déjà terminé avec le tilde-All, mais vous devez changer la ligne complète avec l'autre. C'est donc moins sujet aux erreurs plus tard.

cordialement

15
blabla999

Juste une note latérale, lorsque vous utilisez

All = Cash | Check | CreditCard

vous avez l'avantage supplémentaire que Cash | Check | CreditCard correspondrait à All et non à une autre valeur (-1) qui n'est pas égale à tout en contenant toutes les valeurs. Par exemple, si vous utilisez trois cases à cocher dans l'interface utilisateur

[] Cash
[] Check
[] CreditCard

et additionner leurs valeurs, et l'utilisateur les sélectionne tous, vous verriez All dans l'énumération résultante.

10
configurator

Pour ceux qui ont trouvé cette question éclairante, j'ai un rapide ~ exemple à partager. L'extrait suivant de l'implémentation d'une méthode Paint, comme détaillé dans cette documentation Mono , utilise ~ avec grand effet:

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

Sans le ~ opérateur, le code ressemblerait probablement à ceci:

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

... car l'énumération ressemble à ceci:

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
}

Remarquez la similitude de cette énumération avec la réponse de Sean Bright?

Je pense que le plus important à retenir pour moi est que ~ est le même opérateur dans une énumération que dans une ligne de code normale.

9
Mike

C'est un opérateur complémentaire, voici un article auquel je me réfère souvent pour les opérateurs au niveau du bit

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

Aussi msdn l'utilise dans leur article enums qui démontre qu'il utilise mieux

http://msdn.Microsoft.com/en-us/library/cc138362.aspx

5
missaghi

J'ai fait quelques expériences avec le ~ et je trouve qu'il pourrait avoir des pièges. Considérez cet extrait de code pour LINQPad qui montre que la valeur Enum All ne se comporte pas comme prévu lorsque toutes les valeurs sont orées ensemble.

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 
}
1
Gavin

L'alternative que j'utilise personnellement, qui fait la même chose que la réponse de @Sean Bright mais qui me semble meilleure, est celle-ci:

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

Remarquez comment la nature binaire de ces nombres, qui sont tous des puissances de deux, rend l'affirmation suivante vraie: (a + b + c) == (a | b | c). Et à mon humble avis, + regarde mieux.

1
Camilo Martin

Je veux juste ajouter, si vous utilisez l'énumération [Flags], alors il peut être plus pratique d'utiliser l'opérateur de décalage gauche au niveau du bit, comme ceci:

[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
}
0
sad_robot