В методе расширения как создать объект на основе класса реализации - PullRequest
3 голосов
/ 10 мая 2010

В методе расширения как создать объект на основе класса реализации. Поэтому в приведенном ниже коде я хотел добавить метод расширения «AddRelationship», однако я не уверен, как в рамках метода расширения я могу создать объект Relationship? т.е. не хочу связывать метод расширения с этой конкретной реализацией отношения

   public static class TopologyExtns
    {

        public static void AddNode<T>(this ITopology<T> topIf, INode<T> node)
        {
            topIf.Nodes.Add(node.Key, node);
        }

        public static INode<T> FindNode<T>(this ITopology<T> topIf, T searchKey)
        {
            return topIf.Nodes[searchKey];
        }

        public static bool AddRelationship<T>(this ITopology<T> topIf, INode<T> parentNode, INode<T> childNode)
        {
            var rel = new RelationshipImp();  // ** How do I create an object from teh implementation 
            // Add nodes to Relationship
            // Add relationships to Nodes
        }
    }


    public interface ITopology<T>
    {
        //List<INode> Nodes { get; set; }
        Dictionary<T, INode<T> > Nodes { get; set; }
    }

    public interface INode<T> 
    {
        // Properties
        List<IRelationship<T>> Relationships { get; set; }
        T Key { get; }
    }

    public interface IRelationship<T>
    {
        // Parameters
        INode<T> Parent { get; set; }
        INode<T> Child { get; set; }
    }


namespace TopologyLibrary_Client
{

    class RelationshipsImp : IRelationship<string>
    {
        public INode<string> Parent { get; set; }
        public INode<string> Child { get; set; }
    }
}

    public class TopologyImp<T> : ITopology<T>
    {
        public Dictionary<T, INode<T>> Nodes { get; set; }
        public TopologyImp()
        {
            Nodes = new Dictionary<T, INode<T>>();
        }

    }

спасибо

Ответы [ 3 ]

2 голосов
/ 10 мая 2010

Вы можете добавить дополнительный параметр типа, представляющий класс реализации отношений, указав ограничения, которые должны быть IRelationship и иметь конструктор без параметров:

public static bool AddRelationship<T,R>(this ITopology<T> topIf, INode<T> parentNode, INode<T> childNode) 
    where R : IRelationship, new() {
    var rel = new R();
    // ...
}

Затем вы должны назвать его так, чтобы указать конкретный тип IRelationship (параметр типа 'R'):

topology.AddRelationship<string, RelationshipImp>(parentNode, childNode);

РЕДАКТИРОВАТЬ : альтернативный подход, без метода расширения: вы определяете (и позднее создаете экземпляр) класс RelationshipFactory:

class RelationshipFactory<R> 
    where R : IRelationship, new(){
    // no longer an extension method:
    public static bool AddRelationship<T>(ITopology<T> topIf, INode<T> parentNode, INode<T> childNode) {
        var rel = new R();
        // ...
    }
}
1 голос
/ 10 мая 2010

Решение другой (возможной) проблемы с вашим дизайном. Почему вы используете методы расширения, когда вы можете просто поместить метод AddRelationship в реализацию вашей топологии? Есть ли особая необходимость использовать методы расширения в этом случае? Кроме того, будет ли когда-нибудь случай, когда один узел может иметь много родителей?

Я думаю, что-то вроде этого будет в порядке:

public interface INode<T> 
{
    // Properties
    INode<T> Parent { get; }
    IEnumerable<INode<T>> Children { get; }
    String Key { get; }

    void AddChild(INode<T> child);
}

public class Node<T> : INode<T>
{
    public Node(String key) : this(key, null) {}
    public Node(String key, INode<T> parent)
    {
        this.Parent = parent;
        this.Children = new List<T>();
        this.Key = key; 
    }

    public virtual INode<T> Parent { get; protected set; }
    public virtual String Key { get; protected set; }
    public virtual List<T> Children { get; protected set; }

    public void AddChild(INode<T> node) 
    {
        this.Children.Add(node);
    }
}

Нет необходимости в методах расширения или промежуточном классе IRelationhip. Все это зависит от возможности изменить интерфейс для одного, и что у INode может быть только один родительский элемент.

Редактировать (на основе комментария от ОП):

Учитывая, что вы специально сделали API для метода расширения более чистым, вы можете сделать это:

public static bool AddRelationship(this INode<T> node, IRelationship<T> relationship) 
{
    if (node.Relationships == null)
        node.Relationships = new List<T>;

    if (relationship == null) throw new ArgumentNullException("relationship");

    node.Relationships.Add(relationship);
    return true; // I'd make this method void
}

И тогда вызов этого будет:

INode node = new Node<String>("some key");
INode someParent = new Node<String>("some parent key");
INode someChild = new Node<String>("some child key");

node.AddRelationship(new RelationshipImp(someParent, someChild));

Я не проверял это, так что я могу быть не в курсе, где указаны дженерики. Я не знаю, может ли механизм вывода вывести то, что ему нужно здесь.

Что интересно, почему вы решили использовать «узел имеет много родителей и много детей» вместо «узел имеет соседей»? Недавно я построил структуру графа и нашел словарь или список узлов более чем подходящим для моделирования направлений. Просто снова перечитываю исходный вопрос - должны ли отношения храниться в топологии? В этом было бы гораздо больше смысла, и это то, что вы пытаетесь сделать с помощью своего оригинального метода расширения.

В случае, когда отношения находятся в Топологии, я бы пошел с другим опубликованным ответом:

public static bool AddRelationship<T,R>(this ITopology<T> top, INode<T> parent, INode<T> child ) where R : IRelationship, new
{
    IRelationship<T> rel = new R();
    rel.Parent = parent;
    rel.Child = child;
    top.Relationships.Add(rel);
}

И называя это:

ITopology<String> top = new TopologyImp<String>;
top.AddRelationship<RelationshipImp>(new NodeImp("parent"), new NodeImp("Child"));
1 голос
/ 10 мая 2010

Один из способов - передать ответственность классам ITopology<T> или INode<T>, изменив их интерфейсы для поддержки фабричного метода IRelationship<T>, например, ITopology<T> можно изменить следующим образом:

public interface ITopology<T>
{
    IRleationship<T> CreateRelationship(INode<T> parent, INode<T> child);
    Dictionary<T, INode<T> > Nodes { get; set; }
}

И тогда AddRelationship<T> будет выглядеть примерно так:

public static bool AddRelationship<T>(this ITopology<T> topIf, INode<T> parentNode, INode<T> childNode)
{
    var relationship = topIf->CreateRelationship(parentNode, childNode);
    // ...
}

Поскольку вы используете методы расширения, изменение интерфейсов может быть невозможным или нежелательным, но это вариант.

...