6

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?

15
  • Is it really legal in C# 10 to add the protected keywords in the class when you also have explicit interface implementations? And protected SomeMethod() without a return type or void? Commented Oct 28, 2021 at 21:23
  • Protected interface members seem to be entirely pointless, as far anyone's been able to work out, it seems. They can be explicitly implemented, but there's no way to call them on the base class. The spec proposal leaves this as an "Open Issue", and this blog post gave up trying to understand the point Commented Oct 28, 2021 at 21:30
  • 2
    Note that default interface implementations are not available as members of the implementing type. There will be no method on the class type named SampleMethod1. You could cast the object instance to the interface to access it, but the protected keyword explicitly removes the method from the viable overload list so it is unavailable. If it were public in the interface, you could write this in your class: ((IFooBar)this).SampleMethod1("Test String");. Commented Oct 28, 2021 at 21:30
  • @canton7 protected interface methods seems to be a way to add, as you say, methods available to default implementations in interfaces that derive from the one declaring the protected method. It seems to me that the C# compiler design team hasn't seen the rule that "just because you can't doesn't mean you should". It seems to me to be an example of adding features just because they can, but not really having a clear usecase for why they should. I guess the "every feature starts with minus 100 points" rule have gone out the window. Commented Oct 28, 2021 at 21:38
  • 2
    @AlexeiLevenkov Good point, though in this case I feel like the entire -100 point thing on my part relates to the addition of access modifiers for members of interfaces. They should've left it as just void SampleMethod1(), always public through the interface. But, that's just my opinion. Commented Oct 28, 2021 at 22:06

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

Comments

3

It turns out that protected Default Interface Method members must be implemented explicitly by the implementing class, but can only be accessed from derived interfaces.

For example:

public interface IBase
{
    protected string StringProperty { get; set; }
    
    protected void BaseMethod(string param) => Console.WriteLine($"IBase.BaseMethod: {param}");
}

public interface IDerived : IBase
{
    public void DerivedMethod()
    {
        // SampleMethod1, SampleMethod2 and StringProperty are accessible.
        BaseMethod(StringProperty);
    }
}

public class Foo : IDerived
{
    // Protected DIM properties must be explicitly implemented.
    // They can be initialized, interestingly, but are otherwise inaccessible to Foo.
    string IBase.StringProperty { get; set; } = "StringProperty";
    
    public void Test()
    {
        // Public DIM members are available via cast
        ((IDerived)this).DerivedMethod();
    }

    // Protected DIM members can be overridden.
    // There doesn't seem to be a way to access the base method in the override.
    void IBase.BaseMethod(string param) => Console.WriteLine($"Foo.BaseMethod: {param}");
}

SharpLab.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.