2010-05-10 69 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