Click here to Skip to main content
15,896,606 members
Articles / Programming Languages / C#
Alternative
Tip/Trick

See if a Flags enum is valid

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
17 May 2011CPOL 4.5K  
What about a more complete approach?Define a few caches:private static GenericAlias.Dictionary aoCompositeValues = new GenericAlias.Dictionary();private static GenericAlias.Dictionary aoArrayOfValues = new GenericAlias.Dictionary<Type,...
What about a more complete approach?

Define a few caches:

C#
private static GenericAlias.Dictionary<Type, long> aoCompositeValues = new GenericAlias.Dictionary<Type, long>();
private static GenericAlias.Dictionary<Type, long[]> aoArrayOfValues = new GenericAlias.Dictionary<Type, long[]>();


Now some methods to fill the caches (may or may not be private [I do think private is better]):

C#
private static long EnumCompositeValue(Type poType)
{
    if (poType.IsEnum == false)
        throw new ArgumentException("poType.IsEnum == false");
    if (aoCompositeValues.ContainsKey(poType) == false)
    {
        long nCompositeValue = 0;
        foreach (object enumValue in Enum.GetValues(poType))
            nCompositeValue |= Convert.ToInt64(enumValue);
        aoCompositeValues[poType] = nCompositeValue;
    }
    return aoCompositeValues[poType];
}

private static long[] EnumArrayOfValues(Type poType)
{
    if (poType.IsEnum == false)
        throw new ArgumentException("poType.IsEnum == false");
    if (aoArrayOfValues.ContainsKey(poType) == false)
    {
        GenericAlias.List<long> anValues = new GenericAlias.List<long>();
        foreach (object enumValue in Enum.GetValues(poType))
            anValues.Add(Convert.ToInt64(enumValue));
        aoArrayOfValues[poType] = anValues.ToArray();
    }
    return aoArrayOfValues[poType];
}


Then add a few general validation methods:

C#
public static bool EnumIsValid(Enum penumValue, bool plAlloweZero)
{
    Type oType = penumValue.GetType();
    long nValue = Convert.ToInt64(penumValue);
    if (oType.IsDefined(typeof(FlagsAttribute), false))
        if (nValue == 0)
            return plAlloweZero;
        else
            return (EnumCompositeValue(oType) & nValue) == nValue;
    else
        if (Array.IndexOf<long>(EnumArrayOfValues(oType), nValue) < 0)
            return (nValue == 0) && plAlloweZero;
        else
            return true;
}

public static bool EnumIsValid(Type poType, long pnValue, bool plAlloweZero)
{
    if (poType.IsEnum == false)
        throw new ArgumentException("poType.IsEnum == false");
    if (poType.IsDefined(typeof(FlagsAttribute), false))
        if (pnValue == 0)
            return plAlloweZero;
        else
            return (EnumCompositeValue(poType) & pnValue) == pnValue;
    else
        if (Array.IndexOf<long>(EnumArrayOfValues(poType), pnValue) < 0)
            return (pnValue == 0) && plAlloweZero;
        else
            return true;
}


And now use those to create a few generic validation methods:

C#
public static bool IsValid<T>(Enum penumValue)
    where T : struct /* , Enum // the use of System.Enum is not allowed here */
{
    return EnumIsValid(typeof(T), Convert.ToInt64(penumValue), false);
}

public static bool IsValid<T>(Enum penumValue, bool plAlloweZero)
    where T : struct /* , Enum // the use of System.Enum is not allowed here */
{
    return EnumIsValid(typeof(T), Convert.ToInt64(penumValue), plAlloweZero);
}

public static bool IsValid<T>(long pnValue)
    where T : struct /* , Enum // the use of System.Enum is not allowed here */
{
    return EnumIsValid(typeof(T), pnValue, false);
}

public static bool IsValid<T>(long pnValue, bool plAlloweZero)
    where T : struct /* , Enum // the use of System.Enum is not allowed here */
{
    return EnumIsValid(typeof(T), pnValue, plAlloweZero);
}


And lastly we create a few extension methods:
You need to change the access level of 'Class1Test.EnumCompositeValue' to 'protected internal' (if this is in a different class).

C#
public static class Extentions
{
    public static long CompositeValue(this Type poEnumType)
    {
        return Class1Test.EnumCompositeValue(poEnumType);
    }

    public static long CompositeValue(this Enum penumValue)
    {
        return Class1Test.EnumCompositeValue(penumValue.GetType());
    }

    public static bool IsValid(this Enum penumValue)
    {
        return Class1Test.EnumIsValid(penumValue, false);
    }

    public static bool IsValid(this Enum penumValue, bool plAlloweZero)
    {
        return Class1Test.EnumIsValid(penumValue, plAlloweZero);
    }
}


Not to forget a unit-test:

C#
[Test]
public void EnumValidation()
{
    System.Diagnostics.Debugger.Break();
    Assert.False(EnumIsValid((Enum1)0, false));
    Assert.True(EnumIsValid((Enum1)0, true));
    Assert.True(EnumIsValid((Enum1)1, false));
    Assert.True(EnumIsValid((Enum1)2, false));
    Assert.True(EnumIsValid((Enum1)3, false));
    Assert.True(EnumIsValid((Enum1)4, false));
    Assert.True(EnumIsValid((Enum1)5, false));
    Assert.True(EnumIsValid((Enum1)6, false));
    Assert.True(EnumIsValid((Enum1)7, false));
    Assert.False(EnumIsValid((Enum1)8, false));
    System.Diagnostics.Debugger.Break();
    Assert.False(EnumIsValid((Enum2)0, false));
    Assert.True(EnumIsValid((Enum2)0, true));
    Assert.True(EnumIsValid((Enum2)1, false));
    Assert.False(EnumIsValid((Enum2)2, false));
    Assert.True(EnumIsValid((Enum2)3, false));
    Assert.True(EnumIsValid((Enum2)4, false));
    Assert.True(EnumIsValid((Enum2)5, false));
    Assert.False(EnumIsValid((Enum2)6, false));
    System.Diagnostics.Debugger.Break();
    Assert.False(((Enum1)0).IsValid());
    Assert.True(((Enum1)0).IsValid(true));
    Assert.True(Enum1.A.IsValid());
    Assert.True(Enum1.B.IsValid());
    Assert.True(Enum1.C.IsValid());
    Assert.True((Enum1.A | Enum1.B).IsValid());
    Assert.True((Enum1.A | Enum1.C).IsValid());
    Assert.True((Enum1.B | Enum1.C).IsValid());
    Assert.True((Enum1.A | Enum1.B | Enum1.C).IsValid());
    Assert.False(((Enum1)8).IsValid());
}


Regards,
Frans de Wit.
Happy enum'ing :)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
FDW
Netherlands Netherlands
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --