I have been working on a project recently that involves a lot of work with Flags Enums. To aid with this I created a set of Extension Methods:
Add(Of T as Structure)(self as T, value as Int) as T
Add(Of T as Structure)(self as T, values() as Int) as T
Remove(Of T as Structure)(self as T, value as Int) as T
Remove(Of T as Structure)(self as T, values() as Int) as T
Has(Of T as Structure)(self as T, value as Int) as Boolean
HasAll(Of T as Structure)(self as T, values() as Int) as Boolean
HasAny(Of T as Structure)(self as T, values() as Int) as Boolean
Now the last 3 methods I am happy with - they are self explanatory and do what’s expected. The first four however I am less convinced by.
My main problem is how I wrote some code:
Dim state = States.Blank
If someCondition Then state.Add(States.Disabled)
If someOtherCondition Then state.Add(States.Disconnected)
return state
Which to my surprise always returned States.Blank
rather than Disabled
or Disconnected
or a combination of the two. After a lot of close looking, I realised it was because the Add
method was a function and I was not using the return value.
The logical thing seemed to be changing the extension methods to use a reference parameter rather than a value parameter. While this worked in my vb.net library, the second I tried to use it in my C# test project (MSpec), it broke with the following error:
Error Argument 1 must be passed with the ‘ref’ keyword
So it cannot work like this, I have to return the result as a new instance of the enum. I don’t like it, but other Structure based code (such as DateTime, String) work like this too.
On the point of mutability, I think a system like Ruby’s of indicating a destructive method would be good:
stringValue.chomp! //This will modify stringValue
stringValue.chomp //This will return a new instance which has been chomped
But for now I will settle for returning a new instance.