How To : coerce a ref to an enum into a ref to an int.
-
I have a method in a common base class thus : protected bool SetFlag(bool _new, ref int _flags, int _flag, string _pName) { bool __cancelled = false; bool __old = ((_flags & _flag) == _flag); if (!__old.Equals(_new) { if (!(__cancelled = this.RaisePropertyChanging(__old, _new, pName))) { _flags = (_new) ? _flags | _flag : _flags & ~flag; this.RaisePropertyChanged(__old, _new, pName); } } return __cancelled; } In derivatives of the common base I want to use SetFlags as is shown in the example at the end of this post, but I get a message telling me that it can't cast a ref to an AmbientState to an int etc. If I give SetFlag a Type argument then I can only constrain it to a class(reference type) or struct(value type), but in that case I get compile errors stating that bitwise operations cannot be performed on T objects, ie structs. The content of _flags (ambientState in the example) must be changed BEFORE PropertyChanged handlers are invoked. I have a work-around - The _flags parameter is not passed by reference and I've added a delegate method argument to SetFlag that gets invoked between the "flags = ...." and the "this.RaisePropertyChanged...." statements, the delegate looks like private void saveFlags(int _flags) { this.ambientState = (AmbientState) _flags; ) But like all workarounds its ugly and necessitates documenting why the delegate exists etc. Rgds PhilD -- Sample usage of SetFlags follows public class MyClass : CommonBase { AmbientState ambientState = AmbientState.ZeroValue; public bool Morning { get { return ((this.ambientState & AmbientState.Morning) == AmbientState.Morning); } set { this.SetFlag(value, (int) ref this.ambientState, AmbientState.Morning, "Morning"; } } [Flags] private enum AmbientState : int { ZeroValue = 0x0 Morning = 0x1 Afternoon = 0x2 Evening = 0x4 Night = 0x8 ClearSky = 0x10 CirrusSky = 0x02 etc } }
-
I have a method in a common base class thus : protected bool SetFlag(bool _new, ref int _flags, int _flag, string _pName) { bool __cancelled = false; bool __old = ((_flags & _flag) == _flag); if (!__old.Equals(_new) { if (!(__cancelled = this.RaisePropertyChanging(__old, _new, pName))) { _flags = (_new) ? _flags | _flag : _flags & ~flag; this.RaisePropertyChanged(__old, _new, pName); } } return __cancelled; } In derivatives of the common base I want to use SetFlags as is shown in the example at the end of this post, but I get a message telling me that it can't cast a ref to an AmbientState to an int etc. If I give SetFlag a Type argument then I can only constrain it to a class(reference type) or struct(value type), but in that case I get compile errors stating that bitwise operations cannot be performed on T objects, ie structs. The content of _flags (ambientState in the example) must be changed BEFORE PropertyChanged handlers are invoked. I have a work-around - The _flags parameter is not passed by reference and I've added a delegate method argument to SetFlag that gets invoked between the "flags = ...." and the "this.RaisePropertyChanged...." statements, the delegate looks like private void saveFlags(int _flags) { this.ambientState = (AmbientState) _flags; ) But like all workarounds its ugly and necessitates documenting why the delegate exists etc. Rgds PhilD -- Sample usage of SetFlags follows public class MyClass : CommonBase { AmbientState ambientState = AmbientState.ZeroValue; public bool Morning { get { return ((this.ambientState & AmbientState.Morning) == AmbientState.Morning); } set { this.SetFlag(value, (int) ref this.ambientState, AmbientState.Morning, "Morning"; } } [Flags] private enum AmbientState : int { ZeroValue = 0x0 Morning = 0x1 Afternoon = 0x2 Evening = 0x4 Night = 0x8 ClearSky = 0x10 CirrusSky = 0x02 etc } }
The most obvious solution is to set an int value, call the method with a ref to that value, then reset it to the ambientState property, as follows:
public bool Morning {
get { ... }
set {
int as = (int)this.ambientState;
this.SetFlag(value, ref as, ...);
this.ambientState = (AmbientState)as;
}
}Another solution I see is doing the reverse, which is probably better, since you cut down on the responsibility of the user, and to impede type checking for your enum type. Do this as follows:
protected bool SetFlag(bool _new, ref AmbientState _flags, AmbientState _flag, string _pName)
{
int flag = (int)_flag;
int flags = (int)_flags;
bool __cancelled = false;
bool __old = ((flags & flag) == flag);
if (!__old.Equals(_new)
{
if (!(__cancelled = this.RaisePropertyChanging(__old, _new, pName)))
{
flags = (_new) ? flags | flag : flags & ~flag;
this.RaisePropertyChanged(__old, _new, pName);
_flags = (AmbientState)flags;
}
}
return __cancelled;
}And finally, the RECOMMENDED way of doing this, is setting the FlagsAttribute on the enumeration as follows:
[FlagsAttribute]
public enum AmbientState {
...
}This final way allows you to use &, |, and ^ on the values of the enumeration. I'm not sure if you can use ~, but you can always go to find out! Hope this helps,
-Jeff