c# - How to avoid impossible enum values? -
say have following enum:
[flags] enum intflags { = 1 << 0, b = 1 << 1, c = 1 << 2, aandb = | b } and want build helper method sets flags following:
private static intflags set(intflags values, intflags target) { return target | values; } is there flexible way sanity checking? should impossible set values don't exist in enum or not combination of existing values.
stuff following should not possible:
intflags flags = 0; flags = set(0, flags); flags = set((intflags)int.maxvalue, flags); flags = set(~intflags.a, flags); i guess doing check against existing values like:
private static intflags set(intflags values, intflags target) { if (!enum.getvalues(typeof(intflags)).cast<intflags>().contains(values)) throw new argumentexception(); return target | values; } won't work because setting values like
intflags flags = 0; flags = set(intflags.a | intflags.c, flags); should allowed.
i think might work:
intflags set(intflags values, intflags target) { int intvalue; if (int.tryparse(values.tostring(), out intvalue)) { throw new argumentexception(); } ... } but relies on fact i'm using flags attribute on enum.
edit
i found enum.isdefined() method. works nicely
assert.false(enum.isdefined(typeof(intflags), (intflags)int.maxvalue)); assert.false(enum.isdefined(typeof(intflags), 0)); assert.false(enum.isdefined(typeof(intflags), ~intflags.a)); but fails requirements combined values
assert.true(enum.isdefined(typeof(intflags), intflags.a | intflags.c)); //fails
there's no way statically prohibit users of enum creating enum representing value of underlying type. can such validation @ runtime, showed in question.
if you're looking simple enough way of validating, @ runtime, if particular enum value valid combination of flags, that's simple enough check, assuming defined enum values increasing powers of two. such enum valid values go 0 1 less next highest power of two, check become:
if((int)values > 0 && (int)values >= 1 << 3)) throw new argumentexception(); technically remove possible unmapped values must mapping every single value, that's not particularly practical solution.
all you're left if either of aren't option not use enum, instead use own custom type has exact semantics want:
public class intflags { public int value { get; private set; } private intflags(int value) { this.value = value; } public static readonly intflags = new intflags(1); public static readonly intflags b = new intflags(2); public static readonly intflags c = new intflags(4); public static intflags operator |(intflags first, intflags second) { return new intflags(first.value | second.value); } public override bool equals(object obj) { return equals(obj intflags); } public override bool equals(intflags obj) { return obj != null && value == obj.value; } }
Comments
Post a Comment