열거 형 정의에서 물결표 (~)는 무엇입니까?


149

나는 지금까지 C #을 사용한 후에도 여전히 모르는 것을 찾을 수 있다는 사실에 항상 놀랐습니다 ...

인터넷에서 검색을 시도했지만 검색에서 "~"를 사용하면 제대로 작동하지 않으며 MSDN에서 아무것도 찾지 못했습니다 (존재하지 않음)

최근 에이 코드 스 니펫을 보았는데 물결표 (~)는 무엇을 의미합니까?

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

나는 그것을 보려고 조금 놀랐다. 그래서 그것을 컴파일하려고 시도했지만 효과가 있었다. 어떤 도움?


4
이것은 시간이 지남에 따라 열거를 부드럽게 업그레이드 할 수있는 훌륭하고 우아한 솔루션입니다. 불행히도 CA-2217과 충돌하고 코드 분석 :( 사용할 경우 오류가 발생합니다 msdn.microsoft.com/en-us/library/ms182335.aspx
— 제이슨 코인

이제 2020 년이되었는데 게시물을 시작하는 단어와 같은 단어를 생각하고 있습니다. 내가 혼자가 아니라는 것이 기쁘다.
— funkymushroom

답변:


136

~는 단항 보수 연산자입니다-피연산자의 비트를 뒤집습니다.

~0 = 0xFFFFFFFF = -1

2의 보수 산술에서 ~x == -x-1

~ 연산자는 Objective-C / C ++ / C # / Java / Javascript를 포함하여 C에서 구문을 빌린 거의 모든 언어에서 찾을 수 있습니다.


멋지다. 나는 당신이 열거 형에서 그렇게 할 수 있다는 것을 몰랐습니다. 확실히 미래에 사용합니다
— 오리온 에드워즈에게

따라서 All = Int32.MaxValue와 같습니다. 또는 UInt32.MaxValue?
— Joel Mueller

2
모두 = (부호없는 정수) -1 == UInt32.MaxValue. Int32.MaxValue는 관련이 없습니다.
— Jimmy

4
@ Stevo3000 : Int32.MinValue는 0xF0000000이며 ~ 0이 아닙니다 (실제로 ~ Int32.MaxValue 임)
— Jimmy

2
@ Jimim : Int32.MinValue는 0x80000000입니다. 단일 비트 세트 만 있습니다 (F가 제공하는 4 개는 아님).
— ILMTitan

59

나는 그렇게 생각할 것이다 :

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

좀 더 명확 할 것입니다.


10
확실합니다. 단항의 유일한 좋은 효과는 누군가가 열거에 추가하면 모두 자동으로 포함한다는 것입니다. 그럼에도 불구하고 그 이점은 명확성의 부족보다 중요하지 않습니다.
— ctacke

12
나는 그것이 더 명확한 방법을 보지 못합니다. "모두"는 "정확하게이 3 개 세트"또는 "이 열거 형의 모든 것"을 의미합니까? 새 값을 추가하면 All에도 추가해야합니까? 다른 사람 이 All에 새로운 가치를 부여 하지 않은 것을 본다면 의도적 인 것입니까? ~ 0은 명시 적입니다.
— Ken

16
개인적인 취향을 제외하고, ~ 0의 의미가 당신과 나만큼 OP에 분명하다면, 그는 결코이 질문을 처음부터 제기하지 않았을 것입니다. 한 접근 방식과 다른 접근 방식의 명확성에 대해 무엇을 말하는지 잘 모르겠습니다.
— Sean Bright

9
C #을 사용하는 일부 프로그래머는 아직 <<의 의미를 알지 못할 수 있으므로 더 명확하게 코드를 작성해야합니까? 나는 그렇게 생각하지 않는다.
— 커트 콜러

4
@Paul, 그건 미친 짓이야. 사용을 중지합시다; 많은 사람들이 그것의 사용을 이해하지 못하기 때문에 영어로. 또는 그들이 모르는 모든 단어. 와우, 그런 작은 연산자 세트, 그리고 비트가 무엇인지 모르고 조작하는 방법을 모르는 사람들을 위해 코드를 바보로 만들어야합니까?
— 커트 콜러

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

C #의 2 개의 보수 ~0 == -1로 인해 이진 표현에서 모든 비트가 1 인 숫자입니다.


결제 수단에 대한 비트 플래그를 만드는 것 같습니다. 000 = 없음; 001 = 현금; 010 = 점검; 100 = 신용 카드; 111 = 모두
— Dillie-O

2의 보수는 아니고, 모든 비트를 반전시키고 1을 더하여 2의 보수는 여전히 0입니다. ~ 0은 단순히 모든 비트 또는 1의 보수를 반전시킵니다.
— Beardo

아니요, 2의 보수는 단순히 모든 비트를 반전시킵니다.
— 구성자

2
@configurator-맞지 않습니다. 그것들의 보완은 간단한 비트 반전입니다.
— Dave Markle

c #은 두 개의 보수를 사용하여 음수 값을 나타냅니다. 물론 ~는 두 개의 보수가 아니라 단순히 모든 비트를 반전시킵니다. 어디에서 구했는지 잘 모르겠습니다. Beardo
— Johannes Schaub-litb

17

그것보다 낫다

All = Cash | Check | CreditCard

나중에 다른 방법을 추가하면 다음과 같이 말합니다.

PayPal = 8 ,

당신은 이미 물결표로 끝났지 만, 모든 줄을 다른 줄로 바꿔야합니다. 나중에 오류가 발생하기 쉽습니다.

문안 인사


왜 오류가 적은 이유를 말하는 것이 좋습니다. 예를 들어, 데이터베이스 / 이진 파일에 값을 저장 한 다음 열거에 다른 플래그를 추가하면 'All'에 포함됩니다. 즉, 'All'은 플래그는 동일합니다 :).
— Aidiakapi

11

사용시 참고 사항

All = Cash | Check | CreditCard

모든 값을 포함하면서 모든 값과 같지 않은 다른 값 (-1)으로 Cash | Check | CreditCard평가하거나 평가 All하지 않는 추가 이점이 있습니다. 예를 들어 UI에서 3 개의 확인란을 사용하는 경우

[] Cash
[] Check
[] CreditCard

값을 합산하면 사용자가 모든 값을 선택 All하면 결과 열거 형에 표시됩니다.


그래서 당신이 myEnum.HasFlag()대신 사용 하는 이유 : D
— Pyritie

@Pyritie : 귀하의 의견은 내가 한 말과 어떤 관련이 있습니까?
— 구성자

에서와 같이 ... "All"에 ~ 0을 사용하면 비슷한 작업을 수행 할 수 All.HasFlag(Cash | Check | CreditCard)있습니다. ==~ 0에서 항상 작동하지는 않으므로 해결 방법이 될 것 입니다.
— Pyritie

아, 디버거와 함께 표시되는 내용에 대해 이야기했다 ToString하지 사용하는 방법에 대해 - == All.
— 구성자

9

이 질문을 밝히는 다른 사람들을 위해, 나는 ~공유 할 빠른 예가 있습니다. 에 설명 된대로 페인트 메소드의 구현에서 다음 코드는 이 모노 문서 , 사용하는 ~큰 효과를 :

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

~연산자가 없으면 코드는 다음과 같이 보일 것입니다.

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

... 열거 형이 다음과 같기 때문에 :

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
}

이 열거 형이 Sean Bright의 답변과 유사합니까?

필자가 가장 중요하게 생각하는 것은 ~일반적인 코드 줄과 동일한 열거 형 연산자입니다.


두 번째 코드 블록에서 &s 는 아니어야 |합니까?
— ClickRick

@ClickRick, 캐치 주셔서 감사합니다. 두 번째 코드 블록은 실제로 의미가 있습니다.
— Mike


1

@ 개인적으로 사용하는 대안은 @Sean Bright의 답변과 동일한 기능을하지만 나에게 더 좋아 보입니다.

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

이 2의 거듭 제곱 인 숫자의 이진 특성으로 인해 다음과 같은 주장이 어떻게 적용되는지 확인하십시오 (a + b + c) == (a | b | c). 그리고 IMHO, +더 좋아 보인다.


1

~로 실험을 해본 결과 함정이있을 수 있음을 알았습니다. 모든 값이 함께 정렬 될 때 All 열거 형 값이 예상대로 작동하지 않음을 보여주는 LINQPad에 대한이 스 니펫을 고려하십시오.

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 
}

표준은 0 값을
— 가져서는 안되지만

0

[Flags] 열거 형을 사용하는 경우 다음과 같이 비트 왼쪽 시프트 연산자를 사용하는 것이 더 편리 할 수 ​​있습니다.

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

이것은 전혀 질문에 대답하지 않습니다.
— 봉사
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.