문제

하나 이상의 참/거짓 상태에있을 수있는 객체가있는 경우에, 나는 프로그래머가 몇 가지 부울 값을 사용하는 대신 플래그+비트 마스크를 자주 사용하는 이유에 대해 항상 약간 퍼지했습니다.

.NET 프레임 워크 전체에 있습니다. 이것이 가장 좋은 예인지 확실하지 않지만 .NET 프레임 워크에는 다음이 있습니다.

public enum AnchorStyles
{
    None = 0,
    Top = 1,
    Bottom = 2,
    Left = 4,
    Right = 8
}

따라서 앵커 스타일이 주어지면 비트 마스크를 사용하여 어떤 주가 선택되었는지 알아낼 수 있습니다. 그러나 가능한 각 값에 대해 BOOL 특성이 정의 된 BOOL 속성 또는 개별 열거 값의 배열로 동일한 것을 달성 할 수있는 것 같습니다.

물론 내 질문의 주된 이유는 내 코드로 비슷한 관행을 따라야하는지 궁금합니다.

그렇다면 왜이 접근법을 사용합니까?

  • 메모리 소비가 적습니까? (그렇지 않습니다 ~인 것 같다 부울의 배열/구조물보다 적은 소비하는 것처럼)
  • 구조물이나 어레이보다 더 나은 스택/힙 성능?
  • 더 빠른 비교 작업? 더 빠른 값 부가가치/제거?
  • 그것을 쓴 개발자에게 더 편리합니까?
도움이 되었습니까?

해결책

It was traditionally a way of reducing memory usage. So, yes, its quite obsolete in C# :-)

As a programming technique, it may be obsolete in today's systems, and you'd be quite alright to use an array of bools, but...

It is fast to compare values stored as a bitmask. Use the AND and OR logic operators and compare the resulting 2 ints.

It uses considerably less memory. Putting all 4 of your example values in a bitmask would use half a byte. Using an array of bools, most likely would use a few bytes for the array object plus a long word for each bool. If you have to store a million values, you'll see exactly why a bitmask version is superior.

It is easier to manage, you only have to deal with a single integer value, whereas an array of bools would store quite differently in, say a database.

And, because of the memory layout, much faster in every aspect than an array. It's nearly as fast as using a single 32-bit integer. We all know that is as fast as you can get for operations on data.

다른 팁

  • Easy setting multiple flags in any order.

  • Easy to save and get a serie of 0101011 to the database.

Among other things, its easier to add new bit meanings to a bitfield than to add new boolean values to a class. Its also easier to copy a bitfield from one instance to another than a series of booleans.

It can also make Methods clearer. Imagine a Method with 10 bools vs. 1 Bitmask.

Actually, it can have a better performance, mainly if your enum derives from an byte. In that extreme case, each enum value would be represented by a byte, containing all the combinations, up to 256. Having so many possible combinations with booleans would lead to 256 bytes.

But, even then, I don't think that is the real reason. The reason I prefer those is the power C# gives me to handle those enums. I can add several values with a single expression. I can remove them also. I can even compare several values at once with a single expression using the enum. With booleans, code can become, let's say, more verbose.

Raymond Chen has a blog post on this subject.

Sure, bitfields save data memory, but you have to balance it against the cost in code size, debuggability, and reduced multithreading.

As others have said, its time is largely past. It's tempting to still do it, cause bit fiddling is fun and cool-looking, but it's no longer more efficient, it has serious drawbacks in terms of maintenance, it doesn't play nicely with databases, and unless you're working in an embedded world, you have enough memory.

I would suggest never using enum flags unless you are dealing with some pretty serious memory limitations (not likely). You should always write code optimized for maintenance.

Having several boolean properties makes it easier to read and understand the code, change the values, and provide Intellisense comments not to mention reduce the likelihood of bugs. If necessary, you can always use an enum flag field internally, just make sure you expose the setting/getting of the values with boolean properties.

From a domain Model perspective, it just models reality better in some situations. If you have three booleans like AccountIsInDefault and IsPreferredCustomer and RequiresSalesTaxState, then it doesnn't make sense to add them to a single Flags decorated enumeration, cause they are not three distinct values for the same domain model element.

But if you have a set of booleans like:

 [Flags] enum AccountStatus {AccountIsInDefault=1, 
         AccountOverdue=2 and AccountFrozen=4}

or

  [Flags] enum CargoState {ExceedsWeightLimit=1,  
         ContainsDangerousCargo=2, IsFlammableCargo=4, 
         ContainsRadioactive=8}

Then it is useful to be able to store the total state of the Account, (or the cargo) in ONE variable... that represents ONE Domain Element whose value can represent any possible combination of states.

  1. Space efficiency - 1 bit
  2. Time efficiency - bit comparisons are handled quickly by hardware.
  3. Language independence - where the data may be handled by a number of different programs you don't need to worry about the implementation of booleans across different languages/platforms.

Most of the time, these are not worth the tradeoff in terms of maintance. However, there are times when it is useful:

  1. Network protocols - there will be a big saving in reduced size of messages
  2. Legacy software - once I had to add some information for tracing into some legacy software.

Cost to modify the header: millions of dollars and years of effort. Cost to shoehorn the information into 2 bytes in the header that weren't being used: 0.

Of course, there was the additional cost in the code that accessed and manipulated this information, but these were done by functions anyways so once you had the accessors defined it was no less maintainable than using Booleans.

It is for speed and efficiency. Essentially all you are working with is a single int.

if ((flags & AnchorStyles.Top) == AnchorStyles.Top)
{
    //Do stuff
} 
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top