Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow classes to call interface methods with default implementations #3705

Closed
JeroMiya opened this issue Jul 17, 2020 · 5 comments
Closed

Allow classes to call interface methods with default implementations #3705

JeroMiya opened this issue Jul 17, 2020 · 5 comments

Comments

@JeroMiya
Copy link

JeroMiya commented Jul 17, 2020

If you have an interface with a method that has a default implementation, and a target class that implements that interface, the target class cannot call methods in the interface with default implementations unless it overrides them. It can call methods that do not have default implementations when the target class implements the method.

I think it should allow the target class to call the same methods that an interface that derives from that interface can call. Seems a bit inconsistent to me.

    public interface IEcho
    {
        protected string ProtectedEcho(string value) => value;
        public string PublicEcho(string value) => value;
        string NoDefaultImplEcho(string value);
    }

    public interface IEchoSub : IEcho
    {
        public void Test()
        {
            // NOTE 1
            Console.WriteLine(this.ProtectedEcho("This works! but not in TargetClass below..."));

            // NOTE 2
            Console.WriteLine(this.PublicEcho("This also works! but not in TargetClass below..."));

            Console.WriteLine(this.NoDefaultImplEcho("This also works"));
        }
    }

    public class TargetClass : IEcho
    {
        public string NoDefaultImplEcho(string value) => value;

        public void Test()
        {
            // ERROR 1: 'TargetClass' does not contain a definition of 'Echo' etc...
            // This same code is not an error in IEchoSub (see Note 2)
            Console.WriteLine(this.PublicEcho("hello"));

            // This works, but why the ceremony? Error 1 should be eliminated
            Console.WriteLine(((IEcho)this).PublicEcho("hello"));

            // ERROR 2: 'TargetClass' does not contain a definition of 'ProtectedEcho' etc...
            // This same code is not an error in IEchoSub (see Note 1)
            Console.WriteLine(this.ProtectedEcho("hello"));

            // ERROR 3: Cannot access protected member 'IEcho.Echo(string)' via qualifier
            // of type 'IEcho'; The qualifier must be of type 'TargetClass' (or derived from it)
            // NOTE: This SHOULD be an error, but the error message is incorrect, see ERROR 2.
            Console.WriteLine(((IEcho)this).ProtectedEcho("hello"));

            // This works, but not this.PublicEcho("hello") - they should both work
            Console.WriteLine(this.NoDefaultImplEcho("hello"));
        }
    }

Technically there is this workaround but it is quite silly:

    public interface IEcho
    {
        protected string ProtectedEcho(string value) => value;
        public string PublicEcho(string value) => value;
        string NoDefaultImplEcho(string value);
    }

    internal interface ITargetClass : IEcho
    {
        string IEcho.NoDefaultImplEcho(string value) => value;
        public void Test()
        {
            Console.WriteLine(this.PublicEcho("hello"));
            Console.WriteLine(this.ProtectedEcho("hello"));
            Console.WriteLine(this.NoDefaultImplEcho("hello"));
        }
    }
    public class TargetClass : ITargetClass {}
@HaloFour
Copy link
Contributor

Default implementations are not a member of the class. You can think of them more like explicit implementations, but managed by the runtime.

@JeroMiya
Copy link
Author

JeroMiya commented Jul 17, 2020

Default implementations are not a member of the class. You can think of them more like explicit implementations, but managed by the runtime.

Yes, I understand, however I still propose that this be changed. I think classes that implement interfaces with default implementations should be consistent with interfaces that derive from interfaces. It seems inconsistent the way it is now and the ITargetClass workaround seems like unnecessary boilerplate, at least to me.

@Joe4evr
Copy link
Contributor

Joe4evr commented Jul 17, 2020

Isn't this what's supposed to be solved by base(T)? I know that feature got punted to a later version, but I can't find the appropriate issue right now I found it.

@gulshan
Copy link

gulshan commented Jul 19, 2020

Similar issue #2881

@YairHalberstadt
Copy link
Contributor

Closing as duplicate of #2881 and #2337

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants