Search code examples
c#.net-coredefault-interface-member

Why are my C# default interface implementations not being recognized in the concrete class definition?


I have a .Net 6.0 application in Visual Studio 2019. I'm trying to get default interface implementations working. For some reason, it doesn't seem to be recognizing the default implementations in the class definition.

Here is a sample code snippet:

public interface IFooBar
{
    protected bool BoolProperty { get; set; }
    protected Guid StringProperty { get; set; }
    
    protected void SampleMethod1(string param)
    {
    }
    
    protected void SampleMethod2()
    {
    }
}

public class FooBase
{
}

public class Foo : FooBase, IFooBar
{

    protected bool IFooBar.BoolProperty { get; set; }
    protected Guid IFooBar.StringProperty { get; set; }
    
    protected SomeMethod()
    {
        SampleMethod1("Test String");
    }
}

Here is a snippet from my Visual Studio 2019 project file:

<PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <LangVersion>preview</LangVersion>
</PropertyGroup>

Here is the error message I'm seeing.

Error CS0103 The name 'SampleMethod1' does not exist in the current context

I've got two questions/issues:

  1. Why did the compiler require me to define my interface properties as such in my concrete class: protected bool IFooBar.BoolProperty { get; set; } protected Guid IFooBar.StringProperty { get; set; }

  2. Why is the default method implementation not recognized in my concrete class?


Solution

  • Problem

    Interface default implementation requires explicit cast of the instance to that interface type which has the default implementations.

    Fixed code

    public interface IFooBar
    {
        protected bool BoolProperty { get; set; }
        protected Guid StringProperty { get; set; }
    
        void SampleMethod1(string param)
        {
        }
    
        void SampleMethod2()
        {
        }
    }
    
    public class FooBase
    {
    }
    
    public class Foo : FooBase, IFooBar
    {
        bool IFooBar.BoolProperty { get; set; }
        Guid IFooBar.StringProperty { get; set; }
    
        public void SomeMethod()
        {
            ((IFooBar)this).SampleMethod1("Test String"); // Fixed by casting here
        }
    }
    

    Explanation

    There are two approaches to implementing interfaces: implicit and explicit.

    Implicit interface implementation

    The most popular approach. Interface properties are declared the same way as any others:

    public interface IFooBar
    {
        bool BoolProperty { get; set; }
        Guid StringProperty { get; set; }
    }
    
    public class Foo : IFooBar
    {
        public int IntProperty { get; set; }
        public bool BoolProperty { get; set; } // No special syntax required
        public Guid StringProperty { get; set; }
    }
    

    In this case the properties behave just like they any other property that belongs to this class:

    var foo = new Foo();
    
    Console.WriteLine(foo.BoolProperty); // Works - Foo knows about the property
    
    Console.WriteLine(((IFooBar)foo).BoolProperty); // Also works - IFooBar knows about the property
    
    IFooBar foo2 = foo;
    Console.WriteLine(foo2.BoolProperty); // Also works
    

    Explicit interface implementation

    The case of your Foo class. The syntax and behavior differ:

    public interface IFooBar
    {
        bool BoolProperty { get; set; }
        Guid StringProperty { get; set; }
    }
    
    public class Foo : IFooBar
    {
        bool IFooBar.BoolProperty { get; set; } // Important part is the lack of modifier and declaration using "IFooBar." prefix
        Guid IFooBar.StringProperty { get; set; }
    }
    

    These properties will not be visible unless you cast Foo to IFooBar:

    var foo = new Foo();
    
    //Console.WriteLine(foo.BoolProperty); // Error! Foo doesn't know about the property
    
    Console.WriteLine(((IFooBar)foo).BoolProperty); // Works. IFooBar knows about the property
    
    IFooBar foo2 = foo;
    Console.WriteLine(foo2.BoolProperty); // Also works
    

    This is useful when you don't want to automatically show the properties from the interface in your class, make them a little bit hidden, accessible to users who know what they're looking for.

    Conclusion

    Default interface implementations use explicit approach.