Question

I have an interface -though it could also be an abstract class- that should allow its implementers to specify whether they support a particular feature and I'm looking for the best way to achieve that.

There are several choices here:

Looking at BCL, I see that the Stream class has properties like CanRead and CanSeek, which can be used to check if a feature is supported and throws a NotSupportedException, if I do something that is not supported.

public interface IHandler
{
    bool SupportsA { get; }
    bool SupportsB { get; }

    void A();
    void B();
}

This would be an appropriate approach for me, though I have more than a few features that may or may not be supported and I prefer not to define a "SupportsX" property for each one.

I'm also very fond of bitwise Enum values and I think that another way would be:

[Flags]
public enum HandlerFeature
{
    None = 0
    A = 1,
    B = 2,
    C = 4
}

public interface IHandler
{
    HandlerFeature Features { get; }

    void A();
    void B();
    void C();
}

And an extension method like this could be written:
bool Supports<T>(this T handler, HandlerFeature feature) where T : IHandler

Which I think would also be much prettier than the other approach but, I couldn't help but think that if every Enum value would correspond a member in the contract, I should be able to mark those members more explicitly. Then I thought about attributes:

public interface IHandler
{
    [HandlerRequires(Feature.None)]
    HandlerFeature Features { get; }

    [HandlerRequires(Feature.A)]
    void A();

    [HandlerRequires(Feature.B)]
    void B();

    [HandlerRequires(Feature.A | Feature.B)]
    void AB();

    [HandlerRequires(Feature.C)]
    void C();
}

Although I don't know how to leverage an attribute like this in runtime, it definitely makes the interface definition looks explicit enough.

Is there a best-practice for this?
Or another approach you recommend?
Or anything wrong with the ones I specified?

Was it helpful?

Solution

If you have to build an interface that must use all this stuff, I recommend that you do it with Booleans because the developer has to specify a value for that property when he or she is implementing that interface. Using a flagged enum or attributes can result in classes where e.g. method A is not implemented but the developer simply forgot to set the Attribute or enum correctly. In this case, the compiler would not emit an error.

Anyway, I would advise you to not construct such a "fat" interface. I would encourage you to read about the "Interface Segregation Principle" which is part of the SOLID principles of object-oriented design (Google it, you'll find several articles). It states that clients should not be forced to depend on methods they do not use. The consequence of this is that you use multiple small interfaces instead of one that clasps several aspects. Now I don't know the context your working in but if your interface integrates several cross-cutting concerns like e.g. logging besides its basic business capabilities, I would strongly recommend to throw out logging of the interface and use the Decorator pattern instead (also, Google this if you don't know it :-) ).

Hope this helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top