2012-05-19 2 views
5

Хорошо, вот что я хотел бы сделать.Самостоятельная ссылка в интерфейсах

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. 
    } 
} 

В основном, чтобы подвести итог выше пример, у меня есть общий тип обертки типа T. Я хотел бы, что тип обертки, чтобы уведомить все, что он содержит, что в настоящее время содержатся (с копией своей личности !) Если содержащийся объект реализует определенный интерфейс (этот бит я знаю, как это сделать)

Но это сложно! Зачем? Хорошо, потому что общий тип контейнера должен иметь тип.

Помните эту важную строку?

Если REPLACE_THIS является IContainableObject, то все исполнители интерфейса должны использовать IContainerObject, а не имя класса реализации в методе NotifyContained.

Использование варианта реализации в качестве типа контейнера внутри интерфейса еще хуже по очевидным причинам!

Итак, мой вопрос: что мне делать, чтобы REPLACE_THIS представлял класс объекта, реализующего интерфейс?

ответ

4
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: добавить вариант с общим ограничением

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; 
    } 
} 
+0

Спасибо очень! Работает как шарм :) –

+1

Вы можете избежать кастинга, если объявите общее ограничение для T. –

+0

К сожалению, я только что заметил опечатку в моем примере кода, заметив, что вы создали пустой интерфейс для IContainerObject - I Случайно типизированный IContainer, который не может быть доступен IC. Означает ли это, что ваш интерфейс IContainer можно просто удалить? –

1

Может быть, вы знаете, это уже, но если только IContainableObjects разрешены, как T вы можете объявить свой класс, как этот

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

    ... 
} 
+0

Интересное решение! IContainableObject - это необязательный интерфейс. Только для тех, кто этого хочет, поэтому для меня это не жизнеспособный вариант, но в любом другом случае выглядит так, как будто это сработает :) –

Смежные вопросы