简体   繁体   中英

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 Debug class, 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?

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.

If you use Explicit implementation than method is not visible in your class without casting to interface. You will not be able to call

new ExternalClass().GetImportantInfo()

but you can call

((IDebug)new ExternalClass()).GetImportantInfo();

Because of Explicit implementation new keyword is not necessary. You could even add both implementations in one class:

    public class ExternalClass : IDebug
    {
        string IDebug.GetImportantInfo() //Explicit implementation
        {
            return "Explicit";
        }
        public string GetImportantInfo() 
        {
            return nameof(ExternalClass);
        }
    }

Additionally your Debug class does not have to inherit IDebug interface as it inherits ExternalClass. Resharper will show you this as redundant.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM