1

I have an interface such as this one:

    public interface ITestInterface
    {
        int a { get; set; }

        void DoSomething();
    }

Some of my classes are deriving from this interface:

    public class OneClass : ITestInterface
    {
        public int a { get; set; }

        public void DoSomething()
        {
            Console.WriteLine(this.a.ToString());
        }
    }

    public class AnotherClass : ITestInterface
    {
        public int a { get; set; }

        public void DoSomething()
        {
            Console.WriteLine((this.a * 2).ToString());
        }
    }

Since I now need a (large) common method on all classes derived from my interface, I was trying to provide an additional base class for that:

 public class MyBaseClass
    {
        public void LargeCommonMethod()
        {
            Console.WriteLine((this.a * 3).ToString()); // no 'a' on base class
        }
    }

This clearly doesn't work because the base class would also need to implement my interface in order to know about that a field.

I am now asking myself what the best approach would be here:

  • make MyBaseClass inherit from ITestInterface?
  • set LargeCommonMethod() to protected and provide all internal data it uses via arguments? (There's actually a lot of these..)
  • skip the interface all along and replace it with an abstract base class?
  • ...?
3
  • 3
    All of these options are viable. Which one to choose can depend on the semantics of your class, the program's architecture, and also personal preference. Another possibly good approach could be to have the concrete classes both inherit the base class and implement the interface. One gives you functionality and the other declares a contract. Commented Jan 8, 2022 at 10:44
  • another option will be to have IDoSomting interface with this particular method, that inherits from ITestInterface, then your classes can inherits from whatever interface you need and used on the same way. Commented Jan 8, 2022 at 10:50
  • 1
    You can now add default implementations of methods directly to the interface. It's a newer language feature that I've never used, but it's available. You'd still need your base class to implement the interface. Commented Jan 8, 2022 at 16:36

3 Answers 3

3

C# 8 provides a feature precisely for this scenario.

  • Your classes all implement an interface
  • You want to add a method to the interface
  • You don't want a breaking change to all of the existing classes. If you add a method to the interface all of the classes will break unless you find some way to add the method to all of them. (That includes modifying them all to inherit from a new base class.)

That feature is default interface methods.

You can add your method and a default implementation to the interface:

public interface ITestInterface
{
    int a { get; set; }

    void DoSomething();

    void LargeCommonMethod()
    {
        Console.WriteLine((this.a * 3).ToString());
    }
}

Your existing classes that implement the interface will not break. When cast as the interface, you'll be able to call the method which is defined in the interface. You can still modify any class to provide its own implementation, overriding the interface's default implementation.

For the method to be available the object must be cast as the interface - ITestInterface.

A lot of developers - including myself - found this to be an odd feature. But this is the scenario it's for.

Some documentation

The most common scenario is to safely add members to an interface already released and used by innumerable clients.

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

Comments

2

If you require a base implementation for a method then an interface is clearly not the way to go.

I would choose an abstract class instead and get rid of the interface. There is no need to complicate the design basically.

Comments

0

The Adapter pattern could fit your Use case, when you want to keep the ITestInterface consistent:

public interface ITestInterface
{
    int a { get; set; }

    void DoSomething();
}

public class TestInterfaceAdapter : ITestInterface
{
    private readonly ITestInterface _testInterface;

    public int a {
        get => _testInterface.a;
        set => _testInterface.a = value;
    }

    public TestInterfaceAdapter(ITestInterface testInterface)
    {
        _testInterface = testInterface;
    }

    public void DoSomething()
    {
        _testInterface.DoSomething();
    }

    public void LargeCommonMethod()
    {
        Console.WriteLine((this.a * 3).ToString());
    }
}

public class OneClass : ITestInterface
{
    public int a { get; set; }

    public void DoSomething()
    {
        Console.WriteLine(this.a.ToString());
    }
}

public class AnotherClass : ITestInterface
{
    public int a { get; set; }

    public void DoSomething()
    {
        Console.WriteLine((this.a * 2).ToString());
    }
}

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.