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
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.