I was going to ask this same question but decided to be really wary and do some extensive searching - to avoid duplication. Then I found this one - I've edited the title in the hope that it'll become more popular, because it should.
First, we should be aware that an empty interface such as this is also known as a marker interface - this other, unanswered, SO discusses concerns marker interfaces and Scott Wisniewsi's answer (currently top) is interesting when considering the rest of what I'm about to say.
In researching empty interfaces you'll typically stumble across the MSDN topic concerning Code Analysis warning CA1040 which specifically suggests that empty interfaces that don't implement at least two others should be avoided.
By that token - and of course not necessarily implying that Microsoft's coding guidelines are de-facto - in your example, that's exactly what you are doing (and what I want to do also in my current project) and therefore it would pass MS' own litmus test. As a result I'm happy to say 'yes, such an interface is perfectly reasonable'.
For justification, and I think a particularly good example of a reason why the 'at least two interfaces' switch is placed on this rule is similar to the situation I find myself in:
public interface IReadsAResource
{
public byte[] Read(string id);
}
public interface IWritesAResource
{
//returns the id
public string Write(byte[] resource);
}
Given these two interfaces, I can now write a component that expressly states it only needs to read or write:
public class NeedsRead
{
private readonly IReadsAResource Reader;
public NeedsRead(IReadsAResource reader){ Reader = reader; }
}
public class NeedsWrite
{
private readonly IWritesAResource Writer;
public NeedsWrite(IWritesAResource writer){ Writer = writer; }
}
I will now typically choose to implement this interface on a single class ResourceReaderWriter
, given that the data store for the resources will require dependencies that are shared by both method implementations, passing an instance of that when either interface is needed:
var needsRead = new NeedsRead(new ResourceReaderWriter(/* dependencies */));
var needsWrite = new NeedsWriter(new ResourceReaderWriter(/* dependencies */));
But then what if I have a class that needs to both read and write resources? With the interface ecosystem currently in place, I need two constructor parameters:
public class NeedsReadAndWrite{
public NeedsReadAndWrite(IReadsAResource reader, IWritesAResource writer){
/* reader/writer local variables elided */
}
}
Not such a hardship, you might say, but it's causing two problems:
- The implication is that we have two separate instances that are responsible for reading and writing resources; therefore our class cannot be sure that both are consistent with each other. Equally, it cannot be sure that state is managed correctly between the two.
- As a caller, I can of course sidestep this by creating a single instance first, and passing it for both parameters. But that's taking away my ability to create the object in a one-liner and just seems weird.
Anybody who's stuck with me for this long will see where I'm going now :)
The elegant solution is to introduce an interface for a type that supports both reading and writing:
//denotes a component that can both read and write
public interface IReadsAndWritesAResource : IReadsAResource, IWritesAResource
{
}
With this interface, our problematic type can be re-written as
public class NeedsReadAndWrite{
public NeedsReadAndWrite(IReadsAndWritesAResource readerWriter){
/* local variable assignment elided */
}
}
And both these problems are now side-stepped.
Equally it becomes simple to create a basic proxying type that implements this new interface by taking in instances of a reader and a writer and forwarding the read/write calls on to those.
I think this example demonstrates exactly why you would, or perhaps even should, use marker interfaces that pool together two or more others.