2012-09-13 55 views
0

鑑於在鹼庫中定義的下列類/接口:C#通用傳承問題與架庫

public interface IWorkContext { 
    T Node<T>() where T : class, IHierachy<T>; 
    IHierachyItem Node(); 
} 

public interface IHierachyItem { 
    int Id { get; set; } 
    string Title { get; set; } 
} 

public interface IHierachy<T> : IHierachyItem where T : IHierachy<T> { 
    T Parent { get; set; } 
    IList<T> Children { get; set; } 
} 

public class WorkContext { 
    public static IWorkContext Current { 
     get { return DependencyResolver.Current.GetService<IWorkContext>(); } 
    } 
} 

其中有另一個庫內部以下implentation(引用上面的基本庫):

public class DefaultWorkContext : IWorkContext { 
    // Nhibernate session 
    private readonly ISession _session; 

    public DefaultWorkContext(ISession session) { 
     _session = session; 
    } 

    public T Node<T>() where T : class, IHierachy<T> { 
     return _session.Get<T>(2); 
    } 

    public IHierachyItem Node() { 
     return Node<SiteMapNode>(); 
    } 
} 

在哪裏的SiteMapNode在相同的庫中存在(以及被映射到數據庫表):

public class SiteMapNode : IHierachy<SiteMapNode> { 
    public virtual int Id { get; set; } 
    public virtual SiteMapNode Parent { get; set; } 
    public virtual string Title { get; set; } 
    public virtual IList<SiteMapNode> Children { get; set; } 

    public SiteMapNode() { 
     Children = new List<SiteMapNode>(); 
    } 
} 

我可以說下面的訪問節點和獲取父:

var node = WorkContext.Current.Node(); 
var parentNode = ((IHierachy<SiteMapNode>)node).Parent; 

var node2 = WorkContext.Current.Node<SiteMapNode>(); 
var parentNode2 = node2.Parent; 

但是我不喜歡這兩種方法作爲選項1需要的情況和選擇2要求我傳遞一個默認類型。

是否有可能重構此示例,以便我可以像訪問ID和標題一樣訪問父級和子級。

我希望我已經解釋清楚了這個問題。我會很感激的幫助。謝謝

+0

一般來說,展示你想問的條件的最簡單的例子是更好的... –

回答

1

如果您使用顯式類型而不是var,則問題可能會更加清楚。使用var聲明變量不會使變量類型變爲動態變量,它只是讓編譯器找出變量需要的特定類型(並且由於您不清楚它確定的是哪種類型,所以它可能很危險)。因此,如果聲明瞭具有特定類型的變量(無論您是否知道該類型是否爲),則只能訪問該聲明類型知道的內容,除非您正確轉換該類型。

我覺得到底有沒有辦法正是你想要的完成,而不在某個點作爲一個類型參數(在尖括號),或者有明確的轉換指定類型。您顯然希望將非特定的繼承/實現類型轉換爲方便的特定類型,但這需要告訴編譯器特定的類型。

但是你可以通過改變你的方法來接近你想要的東西。如果您使用非通用的IHierarchy會怎麼樣? (也是正確的拼寫)如果...

public inetrface IHierarchy : IHierarchyItem 
{ 
    IHierarchy Parent { get; set; } 
    IList<IHierarchy> Children { get; set; } 
} 

...然後因爲IHierarchyItem是必需的,因而是衆所周知的IHierarchy任何IHierarchy node變量可以訪問node.Parentnode.Children ......也node.Idnode.Title

這種做法很容易處理的層次方面,允許多態性你WorkContext.Current(ETC)的返回值,但它需要從那裏明確鑄造的IHierarchy定義的成員外訪問特定的一類東西。目前尚不清楚可能出於您的目的的問題的多少。

你也可能在它的上面層的通用IHierarchy<T> : IHierarchy由特定類型沒有進一步鑄造允許處理。您可能必須顯式而不是隱式地(在實現類中)定義一個或兩個接口成員,以避免在沒有泛型類型參數的情況下對屬性進行名稱衝突。

編輯補充:

例如,像:

public interface IHierarchy<T> : IHierarchy // Implies IHierarchyItem 
    where T : IHierarchy<T> 
{ ... } // As you had it. 

然後在您的實現類:

public SiteMapNode : IHierarchy<SiteMapNode> // Implies IHierarchy 
{ 
    private SiteMapNode _Parent; 
    private IList<SiteMapNode> _Children; 

    // Implicit implement of IHierarchyItem and members of SiteMapNode itself. 
    int Id { get; set; } 
    string Title { get; set; } 

    // Implicit implementation of IHierarchy<SiteMapNode> members 
    // These are also members of SiteMapNode itself. 

    SiteMapNode Parent 
    { 
     get { return _Parent; } 
     set { _Parent = value; } 
    } 

    IList<SiteMapNode> Children 
    { 
     get return _Children; 
     set _Children = value; 
    } 

    // Explicit implementation of IHierarchy members 
    // The interface prefix is required to distinguish these from the 
    // type-specific members above to declare different return types. 

    IHierarchy IHierarchy.Parent 
    { 
     get { return _Parent; } // Might need (IHierarchy) cast 
     set { Parent = (SiteMapNode)value; } 
    } 

    IList<IHierarchy> IHierarchy.Children 
    { 
     get { return _Children; } // Might need (IList<IHierarchy>) cast 
     set { _Children = (IList<SiteMapNode>)value; } 
    } 
} 

(或者更大膽的嘗試,並有更多的理智檢查在IHierarchy實現中)。我可能錯過了一些其他需要的顯式轉換;我並不認爲列表可以直接用這種方式進行轉換,但是我認爲通過使用IH<T>可以繼承IHierarchy,它可以確保SiteMapNode是一個有效的IHierarchy,因此這兩個列表類型的列表元素都適用於這兩種列表類型)。如果該列表轉換不起作用,那麼您可能必須創建一個自定義泛型集合類來管理這兩個未指定的IHierarchy和通用的IHierarchy <T>。

由於性能方面的原因,您可能需要添加IHierarchy _CastParent;IList<IHierarchy> _CastChildren;成員,並保存這些對象的未指定的IHierarchy類型轉換以避免不必重複進行重新轉換。我建議你總是投射到特定的類型(當從未指定的時候設置),但是你可能會推遲從特定類型投射到未指定的引用,直到它們真正需要。

現在,所有這些,當然,只有當這種額外的複雜性實際上有助於您的需要。它將允許您將層次結構對象作爲未指定的類型處理(可能會在以後或永遠不會轉換時更具體)或作爲特定或通用的層次結構類型,這些類型將保留其類型知識以便在不進行轉換的情況下進行處理。如果您想要將它們作爲特定於類型的層次結構進行處理,您仍然需要在某個點轉換爲特定類型以從未指定的IHierarchy返回類型進行轉換。

+0

謝謝,但我不太清楚我最後跟着你。我剛剛嘗試在非通用IHierachy接口的頂部添加通用接口,但我無法使其工作。如果你能添加一些細節,我會很感激。謝謝 – nfplee

+0

好的@nfplee,我添加了一個我最後提到的例子。有關更多信息,請嘗試搜索:C#顯式接口實現。 –

+0

感謝羅布,非常感謝。 – nfplee