.NET enumerated logic WTF



  • My WTF is that I would think there has to be a simpler way to do this, but I certainly have no idea what it is. I'm trying to figure out a cleaner syntax for determining if a specific flag is set for an enumerated value.  Take for example, this check to see if a thread is suspended:

    <FONT size=2>if( (myThread.ThreadState & ThreadState.Suspended) == ThreadState.Suspended)...</FONT>

    Is there not some tremendously simpler way of writing that??



  • P.S.  Obviously, that's C# and not VB.  I know with VB you CAN just simply do "if myThread.ThreadState AND ThreadState.Suspended".  I was hoping to find some simpler syntax in C#.  Seems strange if there isn't something shorter, since being less verbose is usually the point with the C's.



  • Caveat: I don't know the .NET runtime from a smoking crater.

    That looks like kind of poor encapsulation.  As a consumer of the class I shouldn't need to know that thread state is stored in a bitmap -- I should be able to call 'isSuspended()' (or, as a property, just read from 'suspended').



  • Is there not some tremendously simpler way of writing that??

    Not really -- in fact, that's the only way to do it, since ThreadState is a bitwise flag enumeration. If there were an IsFlagSet() method on enumerations, all it would do is exactly what you're doing. An IsFlagSet() method would be more elegant, yes, but because of the way enumerations are set up (they are essentially derived structs) they would probably be difficult to create -- although with generics in .NET 2.0, it might be easier. Hmm.... there's a chat on C# 3.0 tomorrow, maybe I'll ask about a better way to check flags in the next version.

    Anyway, check out this article on enumerations for more information on how enums are set up.

    I also agree with Hej that there should probably be properties on the Thread class that indicate the various status information, like IsSuspended, IsRunning, IsStopped, etc..... IsAlive just doesn't cut it for what you want.



  • I also agree with Hej...

    Er... I meant Angstrom! Sure wish I could edit my post..... :)



  • Well, if the flags do not share any particular bit (1, 2, 4, 8, 16, 32, etc. instead of 1, 2, 3, 4, 5, 6, 7, etc.), you can reduce the check to just:

    <FONT color=#000080>if( myThread.ThreadState & ThreadState.Suspended )</FONT>

    Note that AFAICT, the flags are set up such that they do not share values so the above should work correctly.  You would still have to check for a particular flag if you were testing for more than one flag and needed to know which one was set (or you could just use two <FONT face="Courier New" size=2>if()</FONT> statements).

    Peace!

    -=- James.

     



  • @jtwine said:

    Well, if the flags do not share any particular bit (1, 2, 4, 8, 16, 32, etc. instead of 1, 2, 3, 4, 5, 6, 7, etc.), you can reduce the check to just:

    <FONT color=#000080>if( myThread.ThreadState & ThreadState.Suspended )</FONT>

    Note that AFAICT, the flags are set up such that they do not share values so the above should work correctly.  You would still have to check for a particular flag if you were testing for more than one flag and needed to know which one was set (or you could just use two <FONT face="Courier New" size=2>if()</FONT> statements).

    Peace!

    -=- James.

     

    Actually, no you can't. Your suggestion will not compile.

    The whole reason to use enums/flags is for type safety. Your statement, <FONT color=#0000ff>myThread.ThreadState & ThreadState.Suspended</FONT>, evaluates to a ThreadState type; if() statements require a bool type, and no, you can't just cast it, you *have* to test if the result is equal to ThreadState.Suspended. This is C#, not C++ -- C# is type safe, C++ is not.

    As for testing against more than one flag, you can test to see if both flag A and flag B are set by doing something along the lines of the following:

    <FONT color=#808080>MyFlags twoFlagTest = MyFlags.A | MyFlags.B;
    if(currentFlags & twoFlagTest == twoFlagTest)
    {
    // both flags are set, so do something about it
    }</FONT>

    Testing if either flag A or flag B is set is somewhat more tricky. If there isn't a zero-value flag on your enumeration, you have to use a complex or statement, like the following:

    <FONT color=#808080>if(currentFlags & MyFlags.A == MyFlags.A || currentFlags & MyFlags.B == MyFlags.B)</FONT>

    If, however, there *is* a zero-value flag on your enumeration, for example, <FONT color=#808080>MyFlags.None</FONT>, you can use some bit-trickery:

    <FONT color=#808080>MyFlags twoFlagTest = MyFlags.A | MyFlags.B;
    if(currentFlags & twoFlagTest != MyFlags.None)
    {
      // One or the other flag is set, so do something about it
    }</FONT>

    <FONT color=#000000>That will only work if you have an item in your enumeration whose internal value is zero, however. </FONT>



  • Testing if either flag A or flag B is set is somewhat more tricky. If there isn't a zero-value flag on your enumeration, you have to use a complex or statement, like the following:

    <FONT color=#808080>if(currentFlags & MyFlags.A == MyFlags.A || currentFlags & MyFlags.B == MyFlags.B)</FONT>

     

    ?? How about:

    if (currentFlags & (MyFlags.A | MyFlags.B))

    -------------------------

    MyFlags.A = 001 (1)

    MyFlags.B = 100 (4)

    MyFlags.A | MyFlags.B = 101

    100 & 101 = 100

    001 & 101 = 001

    101 & 101 = 101

    000 & 101 = 000

    010 & 101 = 000  (Other bits are ignored)



  • <FONT color=#000080>if( myThread.ThreadState & ThreadState.Suspended )</FONT>

    Actually, no you can't. Your suggestion will not compile. ...  This is C#, not C++ -- C# is type safe, C++ is not.

    You are correct - I was thinking in C/C++, not in C# - I am not a .Net coder.

    Peace!



  • You could do

    if ((myThread.ThreadState & ThreadState.Suspended) != 0)



  • @whalemangler said:

    if (currentFlags & (MyFlags.A | MyFlags.B))

    First, if you read my post above, you'll note that this is an invalid expression... if() requires a boolean type, but currentFlags & (MyFlags.A | MyFlags.B) evaluates to the type MyFlags, not bool. You *have* to test that expression against something else to get a boolean. I assume you *actually* mean if((currentFlags & (MyFlags.A | MyFlags.B)) == something). The something I assume you mean is MyFlags.A | MyFlags.B. If that is the case, then read the first example in my last post. A construct like that will test if *both* MyFlags.A *and* MyFlags.B are set, not if *either* MyFlags.A *or* MyFlags.B is set.

    If you *actually* meant exactly what you wrote, implying that your expression evaluates to if(8), if(1), if(9), if(0), and if(0), you would be correct if you were working in C or C++. C#, fortunately, doesn't work that way. I think I've covered that above and in my last post, but again, just in case: if() statments only operate on an expression that evaluates to a boolean value, i.e. true or false. Bitwise operators evaluate to the types involved in the operation: int & int evaluates to int, MyFlags & MyFlags evaluates to MyFlags, bool & bool evaluates to bool, int & float doesn't work. <FONT face="CG Times (W1)" size=2>

    </FONT>


  • @Goplat said:

    You could do

    if ((myThread.ThreadState & ThreadState.Suspended) != 0)

    So you could. I kept ranting about type safety so much that I forgot about promoting an integral type to the enumeration type.



  • ... if() requires a boolean type, but currentFlags & (MyFlags.A | MyFlags.B) evaluates to the type MyFlags, not bool. You *have* to test that expression against something else to get a boolean.

     

    Oops, was in C++ mode, that will autoconvert to a bool (non zero = true)

    if (currentFlags & (MyFlags.A | MyFlags.B) > 0)

    is c# compatable



  • @whalemangler said:

    ... if() requires a boolean type, but currentFlags & (MyFlags.A | MyFlags.B) evaluates to the type MyFlags, not bool. You have to test that expression against something else to get a boolean.

     

    Oops, was in C++ mode, that will autoconvert to a bool (non zero = true)

    if (currentFlags & (MyFlags.A | MyFlags.B) > 0)

    is c# compatable

    Yes, it is, and much more elegant than my suggestions. :)



  • I love your name btw.  I made it my messenger name o' the day.

    [:)]



  • Why thank you.

    I've used it as a signature phrase for years, whenever I *need* to say WHAT THE FU-- ??? but also need to censor myself because of children/old folks/etc. It fit so well when I stumbled on this website that I just had to use it as my handle.



  • As I recall, System.Threading.Thread.ThreadState is an enumeration
    value, not a bitfield, and as such can only hold ONE enumeration value
    at a time...  In other words,  you could simply write:



    if(myThread.ThreadState == ThreadState.Suspended) ...



    It turns out that the integer values of the different ThreadState
    enumeration states are powers of two, but that's beside the point.



  • Hrm.  Okay, I'm a doofus... I'll be quiet now.



  • @Goplat said:

    You could do

    if ((myThread.ThreadState & ThreadState.Suspended) != 0)

    I never like doing that incase some one changes something so that Suspended might be represented by two bits or something. One of those bits means one thing, the other bit means something else and both of them together imply that it is suspended. Could you not just write a quick utility class to place snippets of useful code?

    bool IsAllSet(int value, int flags) {
        return (value & flags) == flags;
    }

    bool IsAnySet(int value, int flags) {
        return (value & flags) != 0;
    }

    Then all you need for ever more is to call, if (Utility.IsAllSet(myThread.ThreadState, ThreadState.Suspended))

    Also, the example for VB
    If myThread.ThreadState And ThreadState.Suspended will not work if you have option strict on, which I would always advise for one's sanity.


  • Actually, this is a rather well understood and common method of checking bitmaps for specified bits.  But if you don't want to see this kind of logic throughout your code, slap it into a method and abstract it in whatever way you want to make it more readable to less experienced developers.

     

    Cheers!  [H]


Log in to reply