Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Self reference in interfaces

Okay, here is what i would like to do.

Class Container<T>
{
    T contained;
    public void ContainObject(T obj)
    {
        contained = obj;
        if(/*Magical Code That Detects If T Implemtns IContainableObject*/)
        {
            IContainableObect c = (IContainableObject)obj;
            c.NotifyContained(self);
        }
    }
}

interface IContainableObject
{
    public void NotifyContained(Container<REPLACE_THIS>);//This line is important, see below after reading code.
}



Class ImplementingType : IContaiableObject
{
    public Container<ImplementingType> MyContainer;
    public void NotifyContained(Container<ImplmentingType> c)
    {
        MyContainer = c;
    }
}




Class Main
{
    public static void Main(args)
    {
        ImplementingType iObj = new ImplementingType();
        Container<ImplementingType> container = new Container();
        container.ContainObject(iObj);
        //iObj.MyContainer should now be pointing to container.
    }
}

Basically, to sum up the above example, I have a generic wrapper type of type T. I would like that wrapper type to notify whatever it contains that it is being contained (with a copy of its self!) IF the contained object implements a specific interface (this bit I know how to do)

But it gets tricky! Why? Well because the container generic needs to have a type.

Remember that important line?

If REPLACE_THIS is IContainableObject, then all implementers of the interface must use IContainerObject, not the name of the implementing class in their NotifyContained method.

Using ImplementingType as the type of the container within the interface is even worse, for obvious reasons!

So my question is, what do I do to make REPLACE_THIS represent the class of the object implementing the interface?

like image 219
Georges Oates Larsen Avatar asked May 19 '12 20:05

Georges Oates Larsen


2 Answers

class Container<T>
{
    T contained;
    public void ContainObject(T obj)
    {
        contained = obj;
        var containable = obj as IContainableObject<T>;
        if(containable != null)
        {
            containable.NotifyContained(this);
        }
    }
}

interface IContainableObject<T>
{
    void NotifyContained(Container<T> c);
}

class ImplementingType : IContainableObject<ImplementingType>
{
    public Container<ImplementingType> MyContainer;
    public void NotifyContained(Container<ImplementingType> c)
    {
        MyContainer = c;
    }
}

EDIT: add version with generic constraint

interface IContainer<T>
{
    void ContainObject(T obj);
}

class Container<T> : IContainer<T> where T : IContainableObject<T>
{
    T contained;

    public void ContainObject(T obj)
    {
        contained = obj;
        contained.NotifyContained(this);
    }
}

interface IContainableObject<T>
{
    void NotifyContained(IContainer<T> c);
}

class ImplementingType : IContainableObject<ImplementingType>
{
    public IContainer<ImplementingType> MyContainer;

    public void NotifyContained(IContainer<ImplementingType> c)
    {
        Debug.WriteLine("notify contained");
        MyContainer = c;
    }
}
like image 148
Phil Avatar answered Sep 17 '22 10:09

Phil


Maybe you know it already, but if only IContainableObjects are allowed as T you can declare your class like this

class Container<T> 
    where T : IContainableObject
{
    public void ContainObject(T obj)
    {
        // Here you know that obj does always implement IContainableObject.
        obj.NotifyContained(this);   
    }

    ...
}
like image 31
Olivier Jacot-Descombes Avatar answered Sep 18 '22 10:09

Olivier Jacot-Descombes