Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Intended purpose of hiding a base class' explicit interface implementation without warning?

Imagine these specifications are from an external dll. A class that implements an interface explicitly:

public interface IDebug
{
    string GetImportantInfo();
}
public class ExternalClass : IDebug
{
    public void DoSomethingImportant()
    {
        System.Diagnostics.Debug.WriteLine("Something important was done...");
    }
    string IDebug.GetImportantInfo() //Explicit implementation
    {
        DoSomethingImportant();
        return nameof(ExternalClass);
    }
}

Then this one is from internal code, where you know you need to implement the interface:

public class Debug : ExternalClass, IDebug
{
    public string GetImportantInfo()
    {
        return nameof(Debug);
    }
}

Now when I'm calling the Debug's GetImportantInfo() method from the subclass, the explicit implementation in the superclass is not called:

static void Main(string[] args)
{
    IDebug test = new Debug();
    var impInfo = test.GetImportantInfo();
    System.Diagnostics.Debug.WriteLine(impInfo); //"Debug"
}

And the only slight hint I seem to get is that I don't get a compile error when adding the IDebug interface to the Debugclass, without implementing the method:

public class Debug : ExternalClass, IDebug
{
}

Why is there no compile warning when you overwrite a superclass's implementation like this? If the base class implements it implicitly, I get a compile warning telling me to use the new keyword. But using the new keyword to overwrite an explicitly implemented method gives a compile warning:

The member 'Program.Debug.GetImportantInfo()' does not hide an inherited member. The new keyword is not required.

Is there an intended purpose for this, or is this a bug? If it's intended, what is the official reasoning?

like image 615
Aske B. Avatar asked Nov 07 '22 20:11

Aske B.


1 Answers

The problem here is that you are using a little known feature of the language: interface re-implementation:

public class Debug : ExternalClass, IDebug
{
    public string GetImportantInfo()
    {
        return nameof(Debug);
    }
}

Why are you redeclaring that Debug implements IDebug if ExternalClass already does? You are re-implementationing the interface, and becuase you are doing such thing, you get no warning; the compiler assumes you know what you are doing.

If you want the behavior you seem to want, simply don't re-implement the interface:

public class Debug : ExternalClass
{
    public string GetImportantInfo()
    {
        return nameof(Debug);
    }
}

If the base class implements it implicitly, I get a compile warning telling me to use the new keyword.

This warning has nothing to do with interface implementation. The warning is simply due to method hiding, you have two methods with the same signature; IDebug is a non factor here, you could put it out of the equation and you'd still get the same warning.

In my colleague's case, he said he had to implement both the base class and the interface because it was an event-based interface.

Well, then tell your colleague to figure out what he wants. If you reimplement the interface, then any call to DoSomething, be it through a Debug typed reference or an IDebug typed reference, should call the reimplemented behavior. Any other behavior would be unexpected and deeply bewildering.

On the other hand, if you need to keep the orignal behavior of the base class if calling DoSomething() through a IDebug typed reference then do not re-implement the interface. What other alternative are you proposing?

Does this mean that you should know about what interfaces the base class implements? Well yes, of course. I find your question about why should anyone know what interfaces any given class you are going to inherit from implements deeply worrisome to be honest.

like image 183
InBetween Avatar answered Nov 14 '22 23:11

InBetween