2010-05-10 36 views
3

在扩展方法中,如何根据实现类创建对象。所以在下面的代码中,我想添加一个“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>>(); 
     } 

    } 

感谢

回答

2

你可以添加上述相互关系实现类的额外的类型参数,指定约束它必须是一个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(); 
     // ... 
    } 
} 
+0

+1 - 这是由最简单的方法远。 – 2010-05-10 07:33:11

+0

当我尝试这个VS试图告诉我,当我从客户端代码调用这个时,应该有AddRelationship方法名称后面的<>。 – Greg 2010-05-10 10:28:20

+0

你可能会给出一个从客户端使用这种方法的例子 – Greg 2010-05-10 10:59:25

1

的一种方法是通过推责任到ITopology<T>INode<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); 
    // ... 
} 

由于您使用的扩展方法,修改接口也许是不可能的或希望的,但它是一个选项。

+0

Chris - 所以在这种情况下,CreateReleatinoship的实际实现将在ITopology实现中不是扩展方法呢? – Greg 2010-05-10 20:52:30

+0

是的,创建关系将是任何实施“ITopology ”的人的责任。如果它更有意义,你也可以将它推入'INode '接口。 – 2010-05-10 22:03:51

1

解决有关您的设计的另一个(可能的)问题。为什么只需将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); 
    } 
} 

无需扩展方法,或中间IRelationship类。这一切都取决于为一个接口修改接口的能力,而一个INode只能有一个父接口。

编辑(基于OP评论):

考虑到你正在为扩展方法的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")); 
+0

嗨Josh - 在一个图中,节点可以有多个父母。我最初的概念是Node/Relationship的实现已经存在,并且可以被命名为任何东西(或者关键字是任何类型),但是我可以使用extn方法来添加图类型搜索例程等。Paolo的答案很好,除了客户端代码需要在调用时指定类型,这对于“易于使用”的扩展库来说有点难看。也许我需要放松我对库的需求,并且包含一个抽象基类,但是使用泛型作为关键字(因此关键字类型可能仍然不同)。 – Greg 2010-05-10 20:51:21

+0

感谢Josh - Re“你为什么决定带着”有许多父母和许多孩子的节点“” - 我的模型将只是节点和关系,但是在关系中有父母和节点ID以将它们绑定在一起+添加信息的关系类型字段。因此,该图可以只保存一个节点字典(如果这有助于搜索,也可以包含关系之一)。这与你的想法有何不同? – Greg 2010-05-10 22:47:45