Reputation: 878
I have this Simple Console program in .NET Core 3.1 with C# 8:
using System;
namespace ConsoleApp34
{
public interface ITest
{
public void test()
{
Console.WriteLine("Bye World!");
}
}
public class Test : ITest
{
public void CallDefault()
{
((ITest)(this)).test();
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
var t = new Test();
t.CallDefault();
}
}
}
I don't understand why the cast is necessary in the line ((ITest)(this)).test();
Test is directly derived from ITest, so, by definition, 'this' IS ITest
Thank you.
Upvotes: 8
Views: 1735
Reputation: 20353
Default interface implementations work similarly to explicit implementations: they can only be called through the interface type, not the implementing type.
To understand why this is so, imagine Test
implemented 2 interfaces with the same method signature; which would be used if there was no cast?
public interface ITest2
{
public void test()
{
Console.WriteLine("Hello World!");
}
}
public class Test : ITest, ITest2
{
public void CallDefault()
{
test(); // Do we use ITest.test() or ITest2.test()?
}
}
It is true that the above syntax could be allowed, and instead generate a compilation error in the case of multiple interfaces, however, this contradicts with the primary motivation behind the introduction of default interface methods:
Default interface methods enable an API author to add methods to an interface in future versions without breaking source or binary compatibility with existing implementations of that interface.
If Test
already implemented ITest
& ITest2
, then test
was added to ITest2
at a later date, this would constitute a breaking change.
Upvotes: 12
Reputation: 3061
It's funny, if you create an extension method then no more cast is needed.
Just did the following in my project:
public static class IXpObjectExtensions
{
public static Mode GetMode(this IXpObject obj) => obj.Mode;
}
Mode is defined with a default implementation in IXpObject in my case.
I can now use obj.GetMode()
without casting the object to the interface.
Upvotes: 3
Reputation: 4975
This behavior is documented here.
Beginning with C# 8.0, you can define an implementation for members declared in an interface. If a class inherits a method implementation from an interface, that method is only accessible through a reference of the interface type. The inherited member doesn't appear as part of the public interface. The following sample defines a default implementation for an interface method:
public interface IControl
{
void Paint() => Console.WriteLine("Default Paint method");
}
public class SampleClass : IControl
{
// Paint() is inherited from IControl.
}
The following sample invokes the default implementation:
var sample = new SampleClass();
//sample.Paint();// "Paint" isn't accessible.
var control = sample as IControl;
control.Paint();
Any class that implements the IControl interface can override the default Paint method, either as a public method, or as an explicit interface implementation.
Upvotes: 3