Làm cách nào để xóa một mục cho en'd enum?


181

Tôi có một enum như:

public enum Blah
{
    RED = 2,
    BLUE = 4,
    GREEN = 8,
    YELLOW = 16
}

Blah colors = Blah.RED | Blah.BLUE | Blah.YELLOW;

Làm thế nào tôi có thể loại bỏ màu xanh lam từ các màu thay đổi?


2
Lưu ý nhỏ: một enum bitwise trong C # sẽ nhận được thuộc tính [Cờ] phía trên nó.
Nyerguds

@Nyerguds, bạn có thể giải thích lý do tại sao nó nên có thuộc tính?
ethane

Nó cung cấp hỗ trợ IntelliSense tốt hơn trong khi gỡ lỗi, vì nó nhận ra các giá trị enum chưa biết là sự kết hợp của các giá trị hiện có.
Nyerguds

1
Nó cũng cung cấp một .ToString()giá trị có ý nghĩa hơn . ví dụ như RED, BLUE, YELLOWhơn 22.
Sinjai

Câu trả lời:


331

Bạn cần &nó với ~(bổ sung) của 'BLUE'.

Toán tử bổ sung về cơ bản đảo ngược hoặc 'lật' tất cả các bit cho kiểu dữ liệu đã cho. Như vậy, nếu bạn sử dụng ANDtoán tử ( &) với một số giá trị (hãy gọi giá trị đó là 'X') và phần bù của một hoặc nhiều bit được đặt (hãy gọi các bit đó Qvà phần bù của chúng ~Q), câu lệnh X & ~Qsẽ xóa bất kỳ bit nào được đặt trong Qtừ Xvà trả về kết quả.

Vì vậy, để loại bỏ hoặc xóa các BLUEbit, bạn sử dụng câu lệnh sau:

colorsWithoutBlue = colors & ~Blah.BLUE
colors &= ~Blah.BLUE // This one removes the bit from 'colors' itself

Bạn cũng có thể chỉ định nhiều bit để xóa, như sau:

colorsWithoutBlueOrRed = colors & ~(Blah.BLUE | Blah.RED)
colors &= ~(Blah.BLUE | Blah.RED) // This one removes both bits from 'colors' itself

hoặc xen kẽ ...

colorsWithoutBlueOrRed = colors & ~Blah.BLUE & ~Blah.RED
colors &= ~Blah.BLUE & ~Blah.RED // This one removes both bits from 'colors' itself

Vì vậy, để tóm tắt:

  • X | Q đặt bit Q
  • X & ~Q xóa bit Q
  • ~X lật / đảo ngược tất cả các bit trong X

1
vì vậy nếu tôi muốn xóa thêm tôi sẽ chỉ làm: & = ~ Blah.BLUE & ~ Blah.Green?
Blankman

11
Tốt hơn làcolors &= ~( Blah.BLUE | Blah.GREEN );
mệnh

2
thật khác thường, tôi chỉ nghĩ làm thế nào để làm điều này một lần nữa khoảng 5 ngày trước :) Câu hỏi này được cập nhật trong hộp thư đến và voila của tôi!
Blankman

Câu trả lời chính xác. Tôi nghĩ rằng bạn có nghĩa là "& =" không "= &" trong các mẫu mã của bạn;)
Dave Jellison

48

Các câu trả lời khác là đúng, nhưng để loại bỏ màu xanh cụ thể ở trên, bạn sẽ viết:

colors &= ~Blah.BLUE;

9

And not nó ...............................

Blah.RED | Blah.YELLOW == 
   (Blah.RED | Blah.BLUE | Blah.YELLOW) & ~Blah.BLUE;

7

Nghĩ rằng điều này có thể hữu ích cho những người khác vấp ngã ở đây như tôi.

Hãy cẩn thận với cách bạn xử lý bất kỳ giá trị enum nào mà bạn có thể đặt thành giá trị == 0 (đôi khi có thể hữu ích khi có trạng thái Không xác định hoặc Không sử dụng cho enum). Nó gây ra vấn đề khi dựa vào các hoạt động thao tác bit này.

Ngoài ra khi bạn có các giá trị enum là sự kết hợp của sức mạnh khác của 2 giá trị, ví dụ:

public enum Colour
{
    None = 0,  // default value
    RED = 2,
    BLUE = 4,
    GREEN = 8,
    YELLOW = 16,
    Orange = 18  // Combined value of RED and YELLOW
}

Trong những trường hợp này, một phương thức mở rộng như thế này có thể có ích:

public static Colour UnSet(this Colour states, Colour state)
{
    if ((int)states == 0)
        return states;

    if (states == state)
        return Colour.None;

    return states & ~state;
}

Và cũng là phương thức Is set tương đương xử lý các giá trị kết hợp (mặc dù theo một cách hơi khó hiểu)

public static bool IsSet(this Colour states, Colour state)
{
    // By default if not OR'd
    if (states == state)
        return true;

    // Combined: One or more bits need to be set
    if( state == Colour.Orange )
        return 0 != (int)(states & state);

    // Non-combined: all bits need to be set
    return (states & state) == state;
}

Dường như với tôi rằng giải pháp đơn giản hơn là tránh sử dụng 0 làm cờ. Tôi thường thiết lập các enum cờ như thế này . Tôi không thấy bạn hưởng lợi như thế nào từ việc chỉ định trạng thái có giá trị bằng 0. Rốt cuộc, toàn bộ vấn đề là bạn có thể quan tâm đến mình với các tên thân thiện với lập trình viên ( Red, Blue, Green) hơn là các giá trị cơ bản, yeah?
Sinjai

Có một nonehoặc unknownhoặc unsetnhập có giá trị == 0 là trong nhiều trường hợp là một điều tốt là bạn có thể không phải lúc nào giả định rằng một giá trị cụ thể là thiết lập mặc định, ví dụ như nếu bạn chỉ có Red, Blue và Green bạn sẽ phải đỏ như giá trị mặc định (ví dụ: giá trị mà enum có khi nó được tạo hoặc người dùng chưa sửa đổi nó?)
Sverrir Sigmundarson

Bạn có thể chỉ có Unset = 1 và sử dụng 1, 2, 4, 8làm giá trị của mình không? Nếu bạn cần một giá trị mặc định, đó là những gì các nhà xây dựng mặc định dành cho, phải không? Tôi muốn giữ mọi thứ rõ ràng nhất có thể vì mục đích dễ đọc và dựa vào enum để mặc định default(int)( 0) khi không được cung cấp giá trị, mặc dù được bất kỳ nhà phát triển nào biết là thông tin, dù sao cũng quá lén lút đối với thị hiếu của tôi. Chỉnh sửa: Oh chờ đã, làm cho Unset = 0 ngăn không cho một cái gì đó Unset | Blue?
Sinjai

Bạn đang đi đúng hướng trong Sinjai chỉnh sửa của mình, việc giữ giá trị unset == 0 thực sự giải quyết được một vài vấn đề. Một là những gì bạn đã đề cập và một là một nếu bạn bỏ đặt tất cả các giá trị enum thì bạn không cần một trường hợp đặc biệt cho "Unset" nếu nó được đặt thành 0. (ví dụ: nếu Red & ~Redsau đó bạn kết thúc bằng 0 thì bạn sẽ phải có mã để kiểm tra trường hợp này và gán Unsetgiá trị rõ ràng )
Sverrir Sigmundarson

Gotcha. Bạn có thường thấy mình đối phó với các cờ chưa đặt?
Sinjai

2

Còn xor (^) thì sao?

Cho rằng FLAG mà bạn đang cố gắng loại bỏ ở đó, nó sẽ hoạt động .. nếu không, bạn sẽ phải sử dụng một &.

public enum Colour
{
    None = 0,  // default value
    RED = 2,
    BLUE = 4,
    GREEN = 8,
    YELLOW = 16,
    Orange = 18  // Combined value of RED and YELLOW
}

colors = (colors ^ Colour.RED) & colors;

1

Để đơn giản hóa enum cờ và làm cho nó có thể tốt hơn để đọc bằng cách tránh bội số, chúng ta có thể sử dụng dịch chuyển bit. (Từ một bài viết hay kết thúc cuộc tranh luận lớn về cờ Enum )

[FLAG]
Enum Blah
{
   RED = 1,
   BLUE = 1 << 1,
   GREEN = 1 << 2,
   YELLOW = 1 << 3
}

và cũng để xóa tất cả các bit

private static void ClearAllBits()
{
    colors = colors & ~colors;
}

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.