给定基库中定义的以下类/接口:
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一样访问Parent和Child。
我希望我已经清楚地解释了这个问题。我很感激你的帮助。感谢
答案 0 :(得分:1)
如果使用显式类型而不是var
,则问题可能会更明确。使用var
声明变量不会使变量类型动态化,它只会让编译器弄清楚变量需要的特定类型(并且它可能很危险,因为您不清楚它确定的类型是什么类型)。
因此,在声明具有特定类型的变量(无论您是否知道该类型是什么)之后,您只能访问声明类型知道的内容,除非您适当地进行转换。
我认为最终没有办法完全准确地完成你想要的东西而不在某个时候指定一个类型作为类型参数(在尖括号中)或显式强制转换。您显然希望将非特定的iherited / implementation类型转换为方便的特定类型,但这需要告诉编译器一个特定的类型。
但是你可以通过改变你的方法来接近你想要的东西。如果您使用非通用IHierarchy
怎么办? (也纠正拼写)如果......
public inetrface IHierarchy : IHierarchyItem
{
IHierarchy Parent { get; set; }
IList<IHierarchy> Children { get; set; }
}
...然后,任何IHierarchy node
变量都可以访问node.Parent
和node.Children
...以及node.Id
和node.Title
,因为IHierarchyItem
是必需的,因此IHierarchy
已知。
这种方法可以轻松处理层次结构方面并允许WorkContext.Current
(等)返回值中的多态,但是需要从那里进行显式转换以访问{{1}定义成员之外的类的特定内容。 1}}。目前尚不清楚可能出于多大程度的问题。
您也可以在其顶部对通用IHierarchy
进行分层,以允许按特定类型进行处理而无需进一步强制转换。您可能必须显式定义一个或两个接口成员,而不是隐式定义(在实现类中),以避免在没有泛型类型参数的情况下对属性进行名称冲突。
已编辑添加:
例如:
IHierarchy<T> : IHierarchy
然后在你的实现类中:
public interface IHierarchy<T> : IHierarchy // Implies IHierarchyItem
where T : IHierarchy<T>
{ ... } // As you had it.
(或者在IHierarchy实现中获得更多的发现并进行更多的健全性检查。)我可能也错过了其他需要的其他显式转换;我并不认为列表可以通过这种方式直接转换,但我认为通过使用IHierarchy&lt; T&gt;继承IHierarchy它确保SiteMapNode是一个有效的IHierarchy,因此列表的元素适用于两种列表类型)。如果该列表转换不起作用,则可能必须创建一个自定义泛型集合类,以将子项作为未指定的IHierarchy和通用IHierarchy&lt; T&gt;进行管理。
出于性能原因,您可能希望添加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 _CastParent;
成员并保存这些对象的未指定IHierarchy强制转换,以避免重复重新创建它们。我建议你总是转换为特定的类型(当从未指定的设置时),但你可能会将特定类型的转换推迟到未指定的引用,直到实际需要它们为止。
现在,所有这一切,当然,只有这种额外的复杂性实际上对你需要的东西有帮助。它允许您将层次结构对象作为未指定的类型(可能在以后或之后更具体地转换)或作为特定或通用层次结构类型来处理,这些类型将保留其类型知识以便在不进行强制转换的情况下进行处理。如果您希望将它们作为特定于类型的层次结构处理,您仍需要在某些时候转换为特定类型以从未指定的IHierarchy返回类型转换。