When defining a C# interface, we can specify a default implementation. We can normally still implement the method in our class to replace it, but why does that not work after a base class is introduced in-between? There are several things going on here, which I don't understand and did not expect, so I hope someone can explain what exactly is happening here.
Here's an example - both assertions succeed, so depending on the static type, different methods are called.
private interface IFunny
{
    void TryToCallMe() { }
}
private class BaseFunny : IFunny;
private class DerivedFunny : BaseFunny
{
    public void TryToCallMe() => throw new InvalidOperationException();
}
[Fact]
public void FunStuff()
{
    ((Action)(() => new DerivedFunny().TryToCallMe())).Should().Throw<InvalidOperationException>();
    ((Action)(() => ((IFunny)new DerivedFunny()).TryToCallMe())).Should().NotThrow<InvalidOperationException>();
}
And a follow-up question: When I change the DerivedFunny declaration like this,
public void IFunny.TryToCallMe() => throw new InvalidOperationException();
the compiler gives an error actually claiming that DerivedFunny does not implement the interface IFunny (which I think it should, as its base class does so).
Finally, I can redefine it like this:
private class DerivedFunny : BaseFunny, IFunny
{
    public void TryToCallMe() => throw new InvalidOperationException();
}
which seems kind of redundant (unless that compiler error is true). With that implementation, the second assertion will now actually fail and the exception be thrown as well. That's the behaviour I initially would have expected (aka this makes it "work for me"), but I would still prefer to understand why.
This happens because DerivedFunny.TryToCallMe is not a method which implements/takes part in IFunny.TryToCallMe dispatch hierarchy, you will get the same behavior with implicit implementation in the intermediate class:
private interface IFunny
{
    void TryToCallMe();
}
private class BaseFunny : IFunny
{
    void IFunny.TryToCallMe(){}
}
BaseFunny will implement the interface and it does not provide options to override this implementation (if you change explicit implementation in BaseFunny then compiler even will hint a bit with the "hides" warnings).
As a workaround in both cases you can:
BaseFunny.TryToCallMe virtual and override it in the DerivedFunnyprivate class BaseFunny : IFunny
{
     public virtual void TryToCallMe()
    {
        // throw new NotImplementedException();
    }
}
private class DerivedFunny : BaseFunny
{
    public override void TryToCallMe() => throw new InvalidOperationException();
}
DerivedFunny:private class DerivedFunny : BaseFunny, IFunny
{
    public void TryToCallMe() => throw new InvalidOperationException();
}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With