22

This is an Academic question. There is arguably an X-Y problem behind it, which I may post separately later. But I am actually specifically interested in the Academic Question, here.


I often find that I have groups of interfaces which all have properties in common. And I want to define a base interface to commonise those, partly for lack of repetition and partly so that I can pass around an object and use the common methods without knowing the exact type.

Maybe I have IFooRepository, IBarRepository, etc., and I can declare IRepository<TEntity>.

Or I have an IHappyBot, ISadBot, IConfusedBot, all of which have IBot in common.

Notably no class would ever directly implement these base interfaces - you'd never have something that implemented just IBot.

If we were talking about a hierarchy of classes, rather than interfaces, then I would say "Ah ... the base thing is an abstract class".

Is there anything analogous that I can do with the interface to document the expectation that IBot isn't going to get directly implemented.

A aspect of it that I'm interested is doing something that you can later detect via reflection, so that when I test my DI setup, I can say "Ah, this interface isn't expected to be bindable, because it's "abstract".


I mainly care about C# myself, but if this feature specifically exists in other major languages it would interesting to hear about it.
helb
  • 7,609
  • 8
  • 36
  • 58
Brondahl
  • 7,402
  • 5
  • 45
  • 74

2 Answers2

15

A philosophical question in response perhaps - But why should a class not be able to implement IBot if it wants to?

What about an abstract class? I might want an abstract base Bot class to implement IBot as a way to check that the Bot base class ticks all the functionality expected of a base Bot.

An interface is about defining what something can / should do, it's a list of functionality. In my mind it doesn't make much sense to say "something can't claim it satisfies this list of functionality".

An abstract class makes sense because sometimes the abstract class needs its implementation holes filled (abstract methods etc). This isn't the case with an interface.

David E
  • 1,384
  • 9
  • 14
5

I wouldn't think so, the implementation details of Interfaces are deliberately hidden from their collaborators. To allow the implementation details of an interface to be specified by the interface contract would be mixing metaphors and doesn't seem to make sense.

If you really want to achieve this, you could introduce a marker Attribute class, say [AbstractInterface], but I think the uses of that would be very limited (and suspect).

Your motivating example, that a DI system needs to know whether an interface is implemented directly or via a super-interface seems unconvincing to me. The DI system can just look for implementations, I would think.

Rich
  • 15,048
  • 2
  • 66
  • 119
  • I think this answer is correct, for the reason that David E expresses. w.r.t. the specific DI system, I want the test to be able to tell the difference between `I can't find implementations for this interface, which is fine because that's expected` and `I can't find implementations for this interface, and this is bad and I need to fail the test to warn the developer that they broke something. The annotation could be an effective (though slightly unpleasant) way to achieve the functionality if I really want it, though. – Brondahl Feb 07 '18 at 12:30
  • 2
    In your DI example though, what you're really saying is "I do not currently intend to use this interface as the type of an injected parameter". But that's not a property of the interface or the classes that implement it - it's a property of all the other code in your project. Your "abstract interface" as described wouldn't stop you trying to create an injected parameter of the base interface, which would leave you open to invalid DI configuration of a different kind – Gareth Feb 07 '18 at 12:50