0

I need to update a class. It has a boolean e.g. IsTypeA.

There are currently two conditions in the system i.e. 1. IsTypeA or 2. not IsTypeA.

This is referenced in a lot of places under the standard conditions if(IsTypeA) do X else do Y. It is also used in integrations and external data, so i am not allowed to change it. I can only add to the class.

We now have a new condition, so IsTypeA needs to have 3 states.

It would seem hacky to have another boolean (say IsTypeB), which trumps the IsTypeA boolean. It would also make the code hard to follow and rubbish if another type, say TypeC, came into play.

What is the best practice for dealing with this scenario please?

I am considering doing the following:

[Obsolete("Please refer to property 'MyType' for new usage", false)]
public bool IsTypeA
{
    get { return _isTypeA; }
    set 
    { 
    _isTypeA = value;

    if (value == true)
        MyType = EnumMyType.TypeA;
    }
}

private EnumMyType _myType;

public EnumMyType MyType
{
    get { return _myType; }
    set { _myType = value; }
}

(I have previously googled. Found this question, which is similar, but in that instance the dev is updating the whole class. I only need to update one property within the class).

Community
  • 1
  • 1
JsAndDotNet
  • 16,260
  • 18
  • 100
  • 123
  • 4
    That seems reasonable. What are your concerns? Once could argue that "TypeA" and "TypeB" should be subclasses so polymorphism can handle everything, but that might be too drastic of a change. – BradleyDotNET Sep 12 '14 at 16:42
  • 3
    I would get rid of the _isTypeA, and instead just get/set the `IsTypeA` property entirely on the current value of `MyType`. – crashmstr Sep 12 '14 at 16:45
  • 1
    I would personally just use an enum. – TyCobb Sep 12 '14 at 16:46
  • @TyCobb and require changing all of the code that currently works fine as it is? – crashmstr Sep 12 '14 at 16:49
  • @crashmstr Yes because it doesn't seem very extensible as it stands now. Would have been better to just have a property that returns the type and use either standard if equals checks or have a `IsType(MyType)` method. I see changes having to made to the "untouchable" code no matter what the solution is if standard `bool` does not cut it. – TyCobb Sep 12 '14 at 16:52

2 Answers2

2

Add an enum with three values TypeA, TypeB and TypeC

  public enum MyType { A, B, C }

then in your class add another property typed as this enum

public MyType ThreeStateType {get; set;}

and delegate from your old property to this new one (with only a getter)...

public bool IsTypeA { get { return ThreeStateType == MyType.A; } }

you can also add setter if external routines need to continue to be able to set the type using the IsTypeA property...

public bool IsTypeA 
{ 
     get { return ThreeStateType == MyType.A; } 
     set { if (value) ThreeStateType = MyType.A; }
         //   in this case it is not clear what to do 
         //   if the external routine sets IsTypeA  to [false]
}
Charles Bretana
  • 143,358
  • 22
  • 150
  • 216
  • 1
    I would avoid the name `ThreeStateType`. What if there is a `TypeD` in the future? (But otherwise, what I would do). – crashmstr Sep 12 '14 at 16:59
  • Thank you everyone for some really valuable input. In this case, I think @Charles solution is neater than my own and will work well. – JsAndDotNet Sep 12 '14 at 18:21
1

It depends on whether while changing the range of values available for IsTypeA you are actually changing its semantic meaning. If yes - then you are obviously breaking the contract of the interface, as information of whether IsTypeA is true are false is irrelevant to the actual state of the object.

So, if previous implementation stated that object is either A or B and thus IsTypeA is either true or false, and now object can be A or B or C but it is still essentially true that objects A yields IsTypeA == true and Bs and C yields IsTypeA == false then go with @Charles solution: provide new detailed information in enum while retaining backward compatibility. But if this is not the case, i.e. object C is neither true or false (with regard to IsTypeA) then you have no choice but to upgrade the contract (remove IsTypeA and add enum ObjectType). Imagine external integrations reading IsTypeA == false for object C, while this is actually not the case.

Kuba Wyrostek
  • 6,163
  • 1
  • 22
  • 40