Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Self referencing interface

Tags:

c#

xml

interface

This is the kind of thing I want to do:

Interface IMyInterface
{
    List<IMyInterface> GetAll(string whatever)
}

so that classes implementing this must have a function that returns a list of their own type. Is this even possible? I know that - technically - a class implementing this could return a list of other classes which implement this, not necessarily the same class, but I can live with that even though it isn't ideal.

I have tried this, but I can't get the implementing class to correctly implement the method.

like image 939
CompanyDroneFromSector7G Avatar asked Jun 05 '13 09:06

CompanyDroneFromSector7G


People also ask

Can interface reference itself?

Making the interface self-referencing has some serious design implications I'd be wary of. You can no longer just declare a variable of type "IMyInterface". You HAVE to specify a type of interface, which generally defeats the purpose of an interface.

What is Interface Reference?

An interface reference variable only knows that methods which are declared by its interface declaration. It does not allow accessing any other variables or methods that might be supported by the objects. This concept is similar when you use a parent class reference to access a child class object.

Can a TypeScript type reference itself?

When writing out a type or interface in TypeScript for something that will be fed into a recursive function you could cop out and use any or you could properly define the structure. Fortunately, both type and interface allow you to be self referential in terms of defining properties.


3 Answers

Implementing this interface is straight forward:

public class MyInterfaceImpl : IMyInterface
{
    public List<IMyInterface> GetAll(string whatever)
    {
        return new List<IMyInterface> { new MyInterfaceImpl(), this };
    }
}

Please note that the method signature needs to be exactly the same, i.e. the return type has to be List<IMyInterface> and not List<MyInterfaceImpl>.

If you want the type in the list to be the same type as the class that implements the interface, you will have to use generics:

public interface IMyInterface<T> where T : IMyInterface<T>
{
    List<T> GetAll(string whatever)
}

public class MyInterfaceImpl : IMyInterface<MyInterfaceImpl>
{
    public List<MyInterfaceImpl> GetAll(string whatever)
    {
        return new List<MyInterfaceImpl > { new MyInterfaceImpl(), this };
    }
}
like image 131
Daniel Hilgarth Avatar answered Nov 05 '22 04:11

Daniel Hilgarth


This is a normal solution. Consider you have interface IPerson and you want to access each parent of a person. So it would be reasonable to have interface declaration as following:

interface IPerson
{
    IList<IPerson> GetAllParents();
}

Now you are able to get parents of that parents and then get parents... Hope you got the idea. Such design is very flexible, because it allows to model deep dynamic structures using simple static models.

Implementation is very straight-forward:

class Person : IPerson
{
    IList<IPerson> parents;

    public Person(IList<IPerson> parents)
    {
        this.parents = parents;
    }

    public IList<IPerson> GetAllParents()
    {
        return parents;
    }
}

In some sense you need to create some Persons without parents (some kind of Adam and Eve) and then add childs by holding references to their parents. As you can see, my naive model can handle randomly deep family structures, while having very simple interface exposed outside.

like image 2
Ilya Ivanov Avatar answered Nov 05 '22 03:11

Ilya Ivanov


This works for me:

public interface IMyInterface
{
    List<IMyInterface> GetAll(string whatever);
}

public class Program : IMyInterface
{
    public string Member { get; set; }

    public List<IMyInterface> GetAll(string whatever)
    {
        return new List<IMyInterface>()
            { new Program() { Member = whatever } };
    }

    static void Main(string[] args)
    {
        List<IMyInterface> all = new Program().GetAll("whatever");
        Console.WriteLine(all.Count);
    }
}
like image 1
Dialecticus Avatar answered Nov 05 '22 04:11

Dialecticus