Flag enums with multiple zero values...

  • Thread starter Thread starter Nathan Baulch
  • Start date Start date
N

Nathan Baulch

I'm having issues working with some legacy enums that have multiple zero
values.
Whenever I try to call ToString() on one of the non-zero values, all but the
first zero value is included.
Is there any way to get the non-zero value name without resorting to string
manipulation or manually iterating through all values?


[Flags]
enum TestEnum
{
Zero = 0,
AlsoZero = 0,
NonZero = 1
}

static void Main()
{
//all of these output "AlsoZero, NonZero"
Console.WriteLine(TestEnum.NonZero);
Console.WriteLine(Convert.ToString(TestEnum.NonZero));
Console.WriteLine(TypeDescriptor.GetConverter(typeof(TestEnum)).ConvertToString(TestEnum.NonZero));
}


Cheers,
Nathan
 
Unfortunately the enums in question are not defined by me.
Actually, one of them is Microsoft.VisualBasic.MsgBoxStyle in the
Microsoft.VisualBasic assembly.
As you can see below, there are three zero values meaning OkOnly and
DefaultButton1 are appended when calling ToString on any non-zero value.

[Flags]
public enum MsgBoxStyle
{
ApplicationModal = 0,
OkOnly = 0,
DefaultButton1 = 0,
OkCancel = 1,
AbortRetryIgnore = 2,
YesNoCancel = 3,
YesNo = 4,
RetryCancel = 5,
Critical = 0x10,
Question = 0x20,
Exclamation = 0x30,
Information = 0x40,
DefaultButton2 = 0x100,
DefaultButton3 = 0x200,
SystemModal = 0x1000,
MsgBoxHelp = 0x4000,
MsgBoxSetForeground = 0x10000,
MsgBoxRight = 0x80000,
MsgBoxRtlReading = 0x100000,
}

For the time being, I've found a workaround using a TypeConverter and some
simple string manipulation:

static void FlagsEnumTest(Type type, object value)
{
TypeConverter converter = TypeDescriptor.GetConverter(type);
Enum[] items = (Enum[])converter.ConvertTo(value, typeof(Enum[]));
foreach (Enum item in items)
{
if (Enum.IsDefined(type, item))
{
string itemName = item.ToString();
int pos = itemName.LastIndexOf(", ");
if (pos >= 0)
{
itemName = itemName.Substring(pos + 2);
}
Console.WriteLine(itemName);
}
else
{
//contains undefined parts
}
}
}


Patrice said:
Any reason for using the flags attribute ? AFAIK it means that the values
are processed as a set of bit flags... As 0 doesn't change anything a
value for 0 is always included. Generally when you use the flags attribute
you use powers of 2 starting with 1...

Try :
http://msdn2.microsoft.com/en-us/library/system.flagsattribute(VS.80).aspx

---
Patrice

Nathan Baulch said:
I'm having issues working with some legacy enums that have multiple zero
values.
Whenever I try to call ToString() on one of the non-zero values, all but
the first zero value is included.
Is there any way to get the non-zero value name without resorting to
string manipulation or manually iterating through all values?


[Flags]
enum TestEnum
{
Zero = 0,
AlsoZero = 0,
NonZero = 1
}

static void Main()
{
//all of these output "AlsoZero, NonZero"
Console.WriteLine(TestEnum.NonZero);
Console.WriteLine(Convert.ToString(TestEnum.NonZero));

Console.WriteLine(TypeDescriptor.GetConverter(typeof(TestEnum)).ConvertToString(TestEnum.NonZero));
}


Cheers,
Nathan
 
Nathan Baulch said:
Unfortunately the enums in question are not defined by me.
Actually, one of them is Microsoft.VisualBasic.MsgBoxStyle in the
Microsoft.VisualBasic assembly.
As you can see below, there are three zero values meaning OkOnly and
DefaultButton1 are appended when calling ToString on any non-zero value.
[...]

What a strange problem.

On the one hand, at least part of the behavior you're seeing is "by design".
That is, when an enum has the "Flags" attribute, when it gets formatted as a
string all of the values set within the enum instance should be included in
the string.

On the other hand, it seems to me that it ought to include ALL of the zero
values, or NONE (with the latter being preferable). Why the string
formatter should be "smart" enough to recognize that one of the zero values
should not be included, but still wind up including the others is beyond me.

Assuming your workaround is simply "proof-of-concept" and that in real usage
you would actually take each of the individual strings you create and
concatenate them into a full collection of the flags set in the enum
instance, it seems like that's a fine way of dealing with the issue.
However, it seems to me that you shouldn't have to do that, and that you
might want to consider reporting the behavior as a bug.

Pete
 
Looks like the problem MS had is that those values are using both bit fields
for later values and "magic numbers" for lowest numbers...

Try to see what YesNoCancel would give as IMO 0 is not the only problem you
could have.

It's always better to always tell us the whole story. In this particular
case and depending on what you are trying to do, I would likely use the .NET
Framework MessageBox.Show method that doesn't mix those values together...
---
Patrice

Nathan Baulch said:
Unfortunately the enums in question are not defined by me.
Actually, one of them is Microsoft.VisualBasic.MsgBoxStyle in the
Microsoft.VisualBasic assembly.
As you can see below, there are three zero values meaning OkOnly and
DefaultButton1 are appended when calling ToString on any non-zero value.

[Flags]
public enum MsgBoxStyle
{
ApplicationModal = 0,
OkOnly = 0,
DefaultButton1 = 0,
OkCancel = 1,
AbortRetryIgnore = 2,
YesNoCancel = 3,
YesNo = 4,
RetryCancel = 5,
Critical = 0x10,
Question = 0x20,
Exclamation = 0x30,
Information = 0x40,
DefaultButton2 = 0x100,
DefaultButton3 = 0x200,
SystemModal = 0x1000,
MsgBoxHelp = 0x4000,
MsgBoxSetForeground = 0x10000,
MsgBoxRight = 0x80000,
MsgBoxRtlReading = 0x100000,
}

For the time being, I've found a workaround using a TypeConverter and some
simple string manipulation:

static void FlagsEnumTest(Type type, object value)
{
TypeConverter converter = TypeDescriptor.GetConverter(type);
Enum[] items = (Enum[])converter.ConvertTo(value, typeof(Enum[]));
foreach (Enum item in items)
{
if (Enum.IsDefined(type, item))
{
string itemName = item.ToString();
int pos = itemName.LastIndexOf(", ");
if (pos >= 0)
{
itemName = itemName.Substring(pos + 2);
}
Console.WriteLine(itemName);
}
else
{
//contains undefined parts
}
}
}


Patrice said:
Any reason for using the flags attribute ? AFAIK it means that the values
are processed as a set of bit flags... As 0 doesn't change anything a
value for 0 is always included. Generally when you use the flags
attribute you use powers of 2 starting with 1...

Try :
http://msdn2.microsoft.com/en-us/library/system.flagsattribute(VS.80).aspx

---
Patrice

Nathan Baulch said:
I'm having issues working with some legacy enums that have multiple zero
values.
Whenever I try to call ToString() on one of the non-zero values, all but
the first zero value is included.
Is there any way to get the non-zero value name without resorting to
string manipulation or manually iterating through all values?


[Flags]
enum TestEnum
{
Zero = 0,
AlsoZero = 0,
NonZero = 1
}

static void Main()
{
//all of these output "AlsoZero, NonZero"
Console.WriteLine(TestEnum.NonZero);
Console.WriteLine(Convert.ToString(TestEnum.NonZero));

Console.WriteLine(TypeDescriptor.GetConverter(typeof(TestEnum)).ConvertToString(TestEnum.NonZero));
}


Cheers,
Nathan
 
Back
Top