In addition to solutions 1 and 2:
First of all, let me understand the rationale behind that. The purpose of the interface is to… provide some
common interface to some objects of different types, not only classes, but also
struct
types, in an
agnostic manner (agnostic to concrete
runtime types and implementation detail). In this case, the user of these objects gets the reference of the
compile time type which is some interface type. Interface-type reference provides access to all the members of the interface. If some of the members is not implemented, it would mean addressing a non-existent member, trying to reach some random memory area, with unpredictable results.
So, you need to implement all members. But true, sometimes you want some base class which "knows" how to implement only the part of the interface. So, what to do, practically? First of all, note that instantiation of such base class would not make any practical sense. So you may want to make it abstract. And then you still need to implement the whole interface, but some of the implementations could be "dummy". Then the derived class could re-implement the dummy members. This is the simplest trivial example:
interface IDemo {
string First(string input);
void Second();
}
abstract class Base : IDemo {
string IDemo.First(string input) { return input; }
void IDemo.Second() { }
}
class Derived : Base, IDemo {
void IDemo.Second() { DoSomething(); }
void DoSomething() { }
}
Whenever possible, I use
explicit interface member implementations, but you could also implement implicitly (via
public
). See also my last paragraph below for some rationale.
This example is not very good. First of all, it is not obvious, from reading the code, which method implementation is dummy and which is "real". It works but the sensibility of this approach looks questionable. Let's try to invent something more essential:
interface IDemo {
string First(string input);
void Second();
void Third();
}
abstract class Base : IDemo {
string IDemo.First(string input) { return FirstImplementation(input); }
void IDemo.Second() { SecondImplementation(); }
void IDemo.Third() { DoSomethingEssential(); }
protected virtual string FirstImplementation(string input) { return input; }
protected abstract void SecondImplementation();
void DoSomethingEssential() { }
}
class Derived : Base, IDemo {
protected override void SecondImplementation() { DoSomethingReal(); }
void DoSomethingReal() { }
}
Are you getting the idea:
Interface is still fully implemented, but this time, you can clearly tell which implementation is dummy: the one using the abstract method. So, if you create derived class, and if it is non-abstract, the compiler will force you to implement the abstract method. As to the non-abstract virtual method, you are free to either override it or leave the implementation of the
Base
class. Finally, the
Third
method is fully implemented and cannot be overridden, but respective interface member can be reimplemented, like in the first approach described above.
You can combine all these approaches according to your own plan. All I described is applicable to the properties as well, and to the implicit member implementations.
The implicit implementation looks much simpler — please see Solution 1. At the same time, explicit implementation better abstracts implementation from the rest of the class, which is important from the user's point of view: the interface members remain hidden from the user using the class reference, only available to the user of interface reference. This provides better encapsulation, better hides implementation detail.
—SA