65.9K
CodeProject is changing. Read more.
Home

See if a Flags enum is valid

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0 vote)

May 17, 2011

CPOL
viewsIcon

4607

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:
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]):
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:
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:
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).
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:
[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 :)