28

Many times I want to define an interface with some methods that maintain a behavior relationship between them.

However, I feel that many times this relationship is implicit. With that in mind, I asked myself: Is there any way to enforce a behavior relationship between interface methods?

I thought about defining this behavior via inheritance (by defining a common implementation). But since C# does not allow multiple inheritance, I believe that many times an interface would be more advisable and that inheritance is not flexible enough.


For example:

public interface IComponent
{
    void Enable();
    void Disable();
    bool IsEnabled();
}

For this interface, I wanted the following relationship to be fulfilled:

  • If Enable() is called, IsEnabled() should return true.
  • If Disable() is called, IsEnabled() should return false.

In that example, the behavior constraint that I would want to enforce is:

  • When implementing Enable(), the implementer should ensure that IsEnabled() returns true
  • When implementing Disable(), the implementer should ensure that IsEnabled() returns false

Is there a way to enforce this implementation constraint? Or, the fact that I am thinking about enforcing this kind of constraint is itself a sign that there is a flaw in the design?

9
  • 42
    You are looking at it the wrong way. Based on the name, the Enable() method should attempt to enable the component. This may fail though, there may be requirements that are not met yet, initialization may throw. The IsEnabled() method on the other hand should report the current state. This is different and you should not try to make it the same. Commented Nov 25, 2019 at 18:24
  • 6
    @MartinMaat: just because the specific example is a little bit flawed, it is pretty clear to me what the OP is after. If you want to critize, it would be more constructive to suggest a better example.
    – Doc Brown
    Commented Nov 25, 2019 at 18:49
  • 10
    @MartinMaat's comment doesn't seem like criticism, but rather pointing out that the OP's design is flawed. An interface only specifies what is implemented, but not how.
    – Dan Wilson
    Commented Nov 25, 2019 at 19:04
  • 1
    @DanWilson: the way I interpret this question is: let us for the sake of this example assume the design is ok for some reason and we want to enforce the described behaviour of the given interface. So is there a canonical way in C# which can help to do this (maybe not with interfaces alone, maybe with something else)?
    – Doc Brown
    Commented Nov 25, 2019 at 19:08
  • 2
    @Albuquerque I would argue that you shouldn't try to enforce behavior on consumers for the reasons outlined in Robert Harvey's answer. You could very easily end up with constraint conflicts. For example, if Enable() fails, does IsEnabled() then lie and return true?
    – Dan Wilson
    Commented Nov 25, 2019 at 19:22

8 Answers 8

35

Well, first of all, let's tweak your interface a bit.

public interface IComponent
{
    void Enable();
    void Disable();
    bool IsEnabled { get; }
}

Now then. What could potentially go wrong here? For example, could an exception be thrown in the Enable() or Disable() methods? What state would IsEnabled be in then?

Even if you use Code Contracts, I don't see how IsEnabled can be correlated to the use of your Enable or Disable methods unless those methods are guaranteed to succeed. IsEnabled should represent the actual state your object is in, not some hypothetical state.


That said, all you really need is

public interface IComponent
{
    bool IsEnabled { get; set; }
}

Clear it, and the component disables itself.

3
  • 1
    I am choosing this as the accepted answer because it is what I chose to use. However, for future reference, this answer by @T.Sar-ReinstateMonica and this answer by @DocBrown were really useful and seem to be equally correct. Commented Nov 25, 2019 at 20:11
  • @Albuquerque: IMHO, a single bool Enabled { get; set; } would seem much clearer in terms of what it does and what it's supposed to return. Imagine how ridiculous it would have been if Control.Enabled in Windows Forms was split into 3 separate methods?
    – vgru
    Commented Nov 28, 2019 at 16:52
  • @Groo The author of the answer has just added the bool Enabled { get; set; }. Also, rest assured that I used exactly that in my solution. :) Commented Nov 28, 2019 at 17:05
38

What you are looking for is a well-known approach called Design by Contract. It was supported directly in the framework in version 4.0.

DISCLOSURE: Be careful when adding code contracts to a new project in 2019. Current status of further maintenance by Microsoft is not fully clear, see this SO post, maybe because of missing popularity.

DBC allows to specify preconditions, post-conditions and invariants for functions as well as for interfaces, so you simply have to write a contract which enforces IsEnabled to be true after a call of Enabled().

As other answers have pointed out, there may be alternative designs where these constraints are not necessary, but for the sake of this example, let us assume these requirements are justified for some reason. Then using Code Contracts on Robert Harvey's variant of the example interface may look like this:

using System.Diagnostics.Contracts;

[ContractClass(typeof(ComponentContract))]
public interface IComponent
{
    void Enable();
    void Disable();
    bool IsEnabled { get; } 
}

[ContractClassFor(typeof(IComponent))]
sealed class ComponentContract : IComponent
{
    [Pure]
    public bool IsEnabled => Contract.Result<bool>();

    public void Disable()
    {
        Contract.Ensures(IsEnabled == false);
    }

    public void Enable()
    {
        Contract.Ensures(IsEnabled == true);
    }
}

See here for a short tutorial on code contracts.

Also have a look into my second answer to this question, which offers a solution not depending on libs which may become deprecated in the future.

24
  • 1
    @T.Sar-ReinstateMonica: sure, but where in the question do you read the OP is not after such a solution? I don't think Albuquerque is "asking too much of C# Interfaces", that seem to be only your interpretation of the question.
    – Doc Brown
    Commented Nov 25, 2019 at 19:11
  • 1
    Oh, by all means, don't get me wrong. While my interpretation of the question was a bit too literal (I read it as "how do I force C# interfaces to do this specific thing"), yours opened up another possibility, and is probably the best tool for the OP. (I even upvoted yours, for that matter)
    – T. Sar
    Commented Nov 25, 2019 at 20:03
  • 4
    "It is supported directly in the framework since version 4.0." well yeah somewhat. In practice for all intends and purposes Code Contracts are dead. Not only has it not been ported to Net Core at the last time I checked, the required tooling also hasn't seen any official updates since Visual Studio 2015. I'd strongly recommend nobody to add code contracts to a new project in 2019.
    – Voo
    Commented Nov 26, 2019 at 10:40
  • 1
    @Doc Thanks. As someone who was burnt by adding CC himself to several projects (and then removing it again years later when the maintenance hassle just wasn't worth it anymore), it's somewhat dear to heart to avoid others falling into the same trap.
    – Voo
    Commented Nov 26, 2019 at 11:12
  • 3
    Disclosure that the long-term support for Code Contracts is unclear should be highlighted. This being the most voted answer to this question will certainly encourage people to try it. (I almost did) and that should come with a "be sure you know what you are doing" warning. Commented Nov 26, 2019 at 17:17
32

You're asking too much of C# Interfaces.

C# Interfaces are contracts. They say what pack of methods a given class implements, and they guarantee that those methods will be there if someone calls them.

That said, that is also the only thing C# Interfaces do.

They are completely oblivious to what the implemented methods do. They are free to do whatever they want.

A given class can implement "isEnabled" to always return true. Another one can tie "Disable" to a database call, and refuse to disable if something specific happens.

You can't control any of that. That's not the job of your C# Interface.


How do I enforce this behavior, then?

Use tests.

Make a group of unit tests that can accept an object of the type in question, and tests the behavior.

If the test passes, you're good to go. If they fail, something is amiss and you should check your code.

That said, you have no elegant way of forcing this to a third party if you're developing an API, nor should you have. That's not what C# Interfaces are for.

17
  • 6
    @Deduplicator I'm not sure if we're talking about the same thing. C# Interfaces can't have more than public definitions. They certainly can't hold behavior, much less variables.
    – T. Sar
    Commented Nov 25, 2019 at 18:49
  • 6
    Although the 'no implementation' limitation is being relaxed a bit with C# 8 in the form of default interface methods.
    – Eric King
    Commented Nov 25, 2019 at 18:56
  • 4
    @Deduplicator I'm only talking about the C# Interface directive. I never switched definitions, but I understand that some of the stuff I have in my answer might be unclear. I'll clarify.
    – T. Sar
    Commented Nov 25, 2019 at 19:09
  • 5
    @Deduplicator That's the (very specific) meaning of contract inside the DbC paradigm. There are other meanings for contracts, in the context of code. Yours is a valid one, but by no means the only one.
    – T. Sar
    Commented Nov 25, 2019 at 20:52
  • 4
    @FilipMilovanović Again, that's one (valid) definition of contract, and one that surpasses the language. I can also define my contracts as being my test suite, or my interface model. Those are also valid definitions of contracts, all equally valid. Deduplicator isn't wrong on his definition, but I stand that mine is also equally valid, if a bit more simplistic.
    – T. Sar
    Commented Nov 26, 2019 at 1:07
22

State transitions can be represented by separate interfaces per state:

public interface IEnabledComponent
{
    IDisabledComponent ToDisabled();
}

public interface IDisabledComponent
{
    IEnabledComponent ToEnabled();
}

This is much more powerful and safe, since you can expose different methods depending on the current state. In particular you wouldn't even need the IsEnabled property.

Alternatively you could have a single really simple interface:

public interface IComponent
{
    bool IsEnabled {get;set;}
}

Here the state is represented in a single member, so no need to coordinate multiple related members.

You would chose the first options if the different states cause different behavior, the second if the enabled-state doesn't affect other behavior.

The fact that you can define a behavioral relationship between different members of an interface indicates that they are expressing the same information and therefore are redundant. To take a simpler example:

interface IComponent 
{
  bool IsEnabled {get;set;}
  bool IsDisabled {get;set;}
}

Here you could define the relationship that if IsEnabled is true, then IsDisabled is false. But this just shows that one of them could be eliminated since it doesn't represent any independent information or behavior.

5
  • But there's a powerful argument for readability by providing both options, even if they mirror each other.
    – Adam B
    Commented Nov 26, 2019 at 15:18
  • 9
    @AdamB: I disagree. The convention in .net is to provide only the "positive" version of a flag property, i.e. IsEnabled. Redundant "convenience" methods may be acceptable on classes but not on interfaces, since this forces all implementers to implement redundant code which just cause needless complexity and risk of bugs.
    – JacquesB
    Commented Nov 26, 2019 at 15:32
  • 3
    Good point about classes vs interfaces.
    – Adam B
    Commented Nov 26, 2019 at 15:35
  • 1
    @AdamB if you really want both Is/IsNot flag you can use extension methods for the second one (lack of extension properties makes code a bit strange, but …) Commented Nov 27, 2019 at 1:55
  • A caveat with the separate-interfaces-per-state approach: If you have an IEnabledComponent, and disable it with ToDisabled(), the IDisabledComponent is returned, but other parts of the code referencing the now-disabled object with IEnabledComponent would still have that reference and may erroneously believe the component is still enabled.
    – BenM
    Commented Nov 28, 2019 at 2:56
5

One more option when you want usage pattern to look "traditional"* but can limit the interface so it does not require methods to be tied together you can use extension methods to "add" missing methods.

In your example interface can just contain IsEnabled {get;set;} and Enable and Disable can be extensions coming as part of your library defining the interface:

public interface IComponent
{
    bool IsEnabled {get;set;}
}

public static class IComponentExtensions
{
    public static void Enable(this IComponent component)
    {
         component.IsEnabled = true;
    } 
    public static void Disable(this IComponent component)
    {
         component.IsEnabled = false;
    } 
}

Note that since instance methods have priority over extensions and concrete classes may implement methods with same signature to force compiler to pick the class specific implementation possibly causing some confusion. On other hand pretty much everyone has significant experience with this pattern in LINQ - so worth considering if your interface can be narrowed down to allow it.


* "traditional" interface in sense of people expecting to have some particular methods on particular types - for example Stream classes in Framework - one expects file to have "Open" and "Close" when regular streams just "new"/"Dispose".

3
  • Adding instance methods to classes that implement the interface isn't going to work because the consumer won't see them unless they are working with the implementing class itself. If all you have is an IComponent then the compiler will use the extension every time.
    – Corey
    Commented Nov 28, 2019 at 12:13
  • @Corey did you every used myList.First()? or you always cast variables like ((IEnumerable<int>)myList).First() before using LINQ methods for example? (Granted for LINQ this is actually feature...) Commented Nov 28, 2019 at 20:44
  • Sure, when I have a List<int>. When I have an IEnumerable<int> then I call the extension because that's all I have. I don't bother with trying to figure out what implementation I have because the extension handles that better in most cases.
    – Corey
    Commented Nov 28, 2019 at 22:35
3

Here is another idea to solve this using a completely different approach than the one shown in my other answer (hence I post it separately): utilize the template method pattern. Again, let us - for the sake of the example, assume the requirement to make IsEnabled work as described is justified for some reason, and you want to make sure it's state is updated correctly.

Then you could replace the interface by an abstract class, make IsEnabled a boolean property which is switched unconditionally (even in case of an exception), and let a user of that abstract class implement two template methods instead of the original ones:

public abstract class Component  // replacement for IComponent 
{
    public bool IsEnabled{get;private set;}

    public void Enable()
    {
       try
       {
          EnableImpl();
       }
       finally
       {
          IsEnabled=true;
       }
    }
    public void Disable()
    {
       try
       {
          DisableImpl();
       }
       finally
       {
          IsEnabled=false;
       }
    }

    protected virtual void EnableImpl();
    protected virtual void DisableImpl();
}

Now, users can override EnableImpl and DisableImpl by their own implementations, whilst the state tracking is guaranteed to be done.

This approach is definitely more standard than my first suggestion and I would not expect it to become deprecated by Microsoft soon.

3
  • Nice. You should not name a class IComponent though.
    – Guran
    Commented Nov 28, 2019 at 10:10
  • @Guran: ok, done. Thanks for the code review ;-)
    – Doc Brown
    Commented Nov 28, 2019 at 10:23
  • 1
    This is the most viable of the answers I think. The only problem with it is when IComponent is not the only interface and you have other abstract base classes that you want to derive from. C# doesn't support multiple inheritance, and as an ex-C++ programmer I used to miss that a lot. Not anymore.
    – Corey
    Commented Nov 28, 2019 at 12:16
0

An alternative solution (which I would not generally recommend, but accomplishes what you are after) would be this.

public class Switch //make sealed if you really want to enforce behaviour
{  

    public bool IsEnabled {get; private set;}

    public void Enable() //make virtual if you don't want to enforce this behaviour
    { 
        IsEnabled = true;
    }

    public void Disable() //make virtual if you don't want to enforce this behaviour
    {
        IsEnabled = false;
    }
}

public interface IComponent {
    Switch Switch{get;}
}
8
  • @DocBrown I should be experienced enough not to post any code before testing it. (And certainly not before coffee). Thanks :)
    – Guran
    Commented Nov 28, 2019 at 7:30
  • Clever...but does not seem to have any advantages compared to just having a boolean get/set property?
    – JacquesB
    Commented Nov 28, 2019 at 7:34
  • @JacquesB I can't see any advantages either, but the OP admitted that the example was wonky.
    – Guran
    Commented Nov 28, 2019 at 7:40
  • @Guran sure, and I upvoted you for actually answering the question with a clever solution.
    – JacquesB
    Commented Nov 28, 2019 at 8:25
  • This is IMHO not particular useful. The requirement of the original interface was clearly to have Enabled and Disabled to be overrideable methods in an IComponent. You now get a "Switch" object completely decoupled from the IComponent object, and it can only switch the boolean flag, but nothing else inside the IComponent itself. That does not look very sensible to me.
    – Doc Brown
    Commented Nov 28, 2019 at 9:26
-1

Simple answer: no.

That’s not what interfaces do. Each element of an interface is independent of every other element. It is up to the implementor as to what happens when called. Your interface can be implemented by anything, and what it does is up to concrete object.

The Disable method could do something entirely unrelated to the Enable method, and the IsEnabled property might return a value that is unrelated to either (for instance a constant value).

Simplest real world example — when your start implementing a interface, it is common to throw a not implemented exception.

It is up to the implementor to figure out how it all hangs together.

Not the answer you're looking for? Browse other questions tagged or ask your own question.