简体   繁体   中英

Declaring member function in interface

Firstly I am pretty new to C#. I would like to have an interface declare a member function like in the following piece of code

interface IMyInterface {
    void MyAction() {
        // do stuff depending on the output of function()
    }
    void Function();
}

here Function is pure virtual and should be implemented by children of IMyInterface . I could use an abstract class instead of an interface but then I could not inherit from other classes... Say for example that MyAction is recursiverly searching a directory for files and applying Function to any file found to make my example clear.

How to change my design in order to overcome the constraint that interfaces cannot implement classes ?

Edit : In C++ what I would do is using templates as such

template<class A>
static void MyAction(const A& a) {
    // do stuff depending on the output of A::Function()
};

class MyClass {
    void Function();
};

I was wondering if there were an elegant way to do this using interfaces in C#.

The only way to directly handle this would be to use an abstract class, as the interface cannot contain "logic" of any form, and is merely a contract.

One alternative, however, would be to make an interface and a static class. You could then place your logic in an extension method using the interface.

public interface IMyInterface {
    void Function();
}

public static class MyInterfaceExtensions {
    public static void MyAction(this IMyInterface object)
    {
       // use object.Function() as needed
    }
}

The main disadvantages here are more types, which reduces maintainability, and a lack of discoverability.

In C# you don't have multiple inheritance. You can circumvent this limitation by using composition .

Define your interface like this ( Function needs not to be defined here):

public interface IMyInterface
{
    void MyAction();
}

Declare an abstract class with an abstract Function and implementing this interface:

public abstract class MyInterfaceBase : IMyInterface
{
    public void MyAction()
    {
        // Do stuff depending on the output of Function().
        Function();
    }

    protected abstract void Function();
}

From this abstract class you can derive a concrete implementation. This is not yet your "final" class, but it will be used to compose it.

public class ConcreteMyInterface : MyInterfaceBase
{
    protected override void Function()
    {
        Console.WriteLine("hello");
    }
}

Now let's come to your "final", composed class. It will derive from SomeBaseClass and implement IMyInterface by integrating the functionality of ConcreteMyInterface :

public class SomeBaseClass
{
}

public class MyComposedClass : SomeBaseClass, IMyInterface
{
    private readonly IMyInterface _myInterface = new ConcreteMyInterface();

    public void MyAction()
    {
        _myInterface.MyAction();
    }
}

UPDATE

In C# you can declare local classes. This comes even closer to multiple inheritance, as you can derive everything within your composing class.

public class MyComposedClass : SomeBaseClass, IMyInterface
{
    private readonly IMyInterface _myInterface = new ConcreteMyInterface();

    public void MyAction()
    {
        _myInterface.MyAction();
    }

    private class ConcreteMyInterface : MyInterfaceBase
    {
        protected override void Function()
        {
            Console.WriteLine("hello");
        }
    }
}

You can define MyAction as extension method :

public interface IMyInterface
{
   void Function();
}

public static class MyInterfaceExtensions
{
    public static void MyAction(this IMyInterface obj)
    {
        obj.Function();
    }
}

Example:

public class HelloWorld : IMyInterface
{
    public void Function()
    {
        Console.WriteLine("Hello World");
    }

    public static void Main(string[] args)
    {
        new HelloWorld().MyAction();
    }
} 

Output:

Hello World

Interfaces can't implement any behavior they are just contracts. If you want to implement some logic while defining a contract you could use an abstract class.

For that purpose . you need to define abstract class. You can provide default implementations or you can leave the implementation to the derived class.

If the derived class want to override some thing they can always do that . This gives them the flexibility to use base along with changes they want to override.

Declare the function's interface (Signature and return types), in an interface, Then create an abstract class that is defined to implement that interface, and implement a basic default implementation in the abstract class. Then, create other concrete classes that inherit from the abstract class, but when necessary, override the abstract classes base implementation with different implementation.

This sort of problem might best be overcome by separating the external behaviours; MyAction in this case, from the internal implementation; MyFunction .

The point here is understanding what should be part of the interface/contract between this class and others, and what should be part of the implementation of that contract.

Here, the contract between this object and its consumers is defined;

interface IMyInterface
{
    void MyAction();
}

Now, a base class which implements this interface, and also enforces a particular behaviour;

abstract class BaseClass : IMyInterface
{
    public void MyAction()
    {
        // do some commmon action

        // call derived implementation to deal with the outcome
    }

    protected abstract void MyFunction();
}

And finally, a concrete implementation which deals with the results of MyFunction in some specific way;

class ConcreteClass : BaseClass
{
    protected override void MyFunction()
    {
         // concrete implementation here
    }
}

An interface is a contract, and cannot contain implementation.

From your statement above:

I could use an abstract class instead of an interface but then I could not inherit from other classes

I believe you are hitting the "why does C# not support multiple inheritance" question.

Here is a CodeProject Article on Simulated Multiple Inheritance for C# . You should be able to follow this pattern to achieve a workaround to the simple inheritance model of C#.

This is a proposed feature for C# 8.0:

interface IA
{
    void M() { WriteLine("IA.M"); }
}

class C : IA { } // OK

IA i = new C();
i.M(); // prints "IA.M"`

https://github.com/dotnet/csharplang/blob/master/proposals/default-interface-methods.md

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM