0

给定基础库中定义的以下类/接口:

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>(); }
    }
}

在另一个库中具有以下实现(引用上面的基本库):

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 和 Title 一样访问父级和子级。

我希望我已经足够清楚地解释了这个问题。我会很感激帮助。谢谢

4

1 回答 1

1

如果您使用显式类型而不是var. 声明变量var不会使变量类型动态化,它只会让编译器确定变量需要的特定类型(这可能很危险,因为您不清楚它确定的类型)。

因此,声明了具有特定类型的变量(无论您是否知道该类型是什么),然后您只能访问该声明的类型知道的内容,除非您适当地转换它。

我认为最后没有办法在不指定类型作为类型参数(在尖括号中)或显式转换的情况下准确地完成你想要的。您显然想将非特定的继承/实现类型转换为方便的特定类型,但这需要告诉编译器特定类型才能成为。

但是通过改变你的方法,你可能会更接近你想要的。如果您使用非泛型IHierarchy怎么办?(同时更正拼写)如果...

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

...然后任何IHierarchy node变量都可以访问node.Parentand node.Children... 并且node.Id因为node.TitleIHierarchyItem必需的,因此是已知的IHierarchy.

这种方法可以轻松处理层次结构方面并允许您的WorkContext.Current(等)返回值中的多态性,但它需要从那里进行显式转换才能访问特定于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 实现中进行更多的完整性检查。)我可能还错过了一些其他需要的显式转换;我不肯定可以以这种方式直接转换列表,但我认为通过让 IHierarchy<T> 继承 IHierarchy 可以确保 SiteMapNode 是有效的 IHierarchy,因此列表的元素适用于两种列表类型)。如果该列表转换不起作用,您可能必须创建一个自定义通用集合类来将子级管理为未指定的 IHierarchy 和通用 IHierarchy<T>。

出于性能原因,您可能希望添加IHierarchy _CastParent;IList<IHierarchy> _CastChildren;成员并保存这些对象的未指定 IHierarchy 强制转换以避免重复重铸它们。我建议您始终转换为特定类型(从未指定的设置时),但您可能会将特定类型的转换推迟到未指定的引用,直到实际需要它们。

现在,所有这一切,当然,只有当这种额外的复杂性实际上有助于满足您的需求时。它将允许您将层次结构对象作为未指定的类型(以后可能会更具体地转换,或者从不转换)或作为特定或通用的层次结构类型来处理,这将保留其类型知识以便在不进行转换的情况下进行处理。如果您想将它们作为特定于类型的层次结构处理,您仍然需要在某些时候转换为特定类型以从未指定的 IHierarchy 返回类型转换。

于 2012-09-13T20:25:38.873 回答