在父子关系中使用泛型

时间:2010-08-02 15:31:39

标签: c# generics

我有一个像这样声明的抽象类BaseItem:

public abstract class BaseItem
{
    public BaseItem Parent { get; protected set; }
    public List<BaseItem> Children = new List<BaseItem>();

    public abstract string Function1();        
}

基本上,我正在尝试实现一个设计,其中每个Item都有一个特定类型的父级和不同类型的子级。

例如,ItemA将拥有所有ItemB类型的子项。然后ItemB将具有ItemA类型的父级和子级所有ItemC类型。 ItemC将具有ItemB的父级和ItemD类型的子级。

我认为使用泛型来做这件事会更加简洁,以避免不必要的演员表,因为我知道我的每个继承类的父和子将是什么类型。所以我想出了类似的东西:

public abstract class AbstractBase
{
    public abstract string Function1();
}

public abstract class BaseItem<T1, T2> : AbstractBase
    where T1 : AbstractBase
    where T2 : AbstractBase
{
    public T1 Parent { get; protected set; }
    public List<T2> Children = new List<T2>();
}

public class ItemA : BaseItem<ItemA, ItemB>
{
}
public class ItemB : BaseItem<ItemA, ItemC>
{
}
public class ItemC : BaseItem<ItemB, ItemD>
{
}
public class ItemD : BaseItem<ItemC, ItemD>
{
}

所以有两件事。 这是一个好设计吗?这样做有更简单/更好的方法吗?我真的不喜欢使用第二个抽象基类只是为了能够使用泛型。 如果我确实这样做,处理目的的最佳方法是什么? (即ItemA在我的实际问题域中没有父级,但它需要一个父级来编译.ProjectD没有子级,但我需要给它一些东西)

5 个答案:

答案 0 :(得分:1)

如果我理解你的话,你说ItemA永远不会有父母而且ItemD从来没有孩子,对吗?说实话,我可能只是声明具有正确类型的父/子属性的单独类:

public abstract class AbstractBase
{
    public abstract string Function1();
}

public class ItemA : AbstractBase
{
    public List<ItemB> Children = new List<ItemB>();
}
public class ItemB : AbstractBase
{
    public ItemA Parent { get; protected set; }
    public List<ItemC> Children = new List<ItemC>();
}
public class ItemC : AbstractBase
{
    public ItemB Parent { get; protected set; }
    public List<ItemD> Children = new List<ItemD>();
}
public class ItemD : AbstractBase
{
    public ItemC Parent { get; protected set; }
}

您在这里重复的唯一事情是ParentChildren属性/字段。您可以在AbstractBase中实现的所有其他常用功能。 (当然,除非该功能需要访问父母/孩子 - 但即使在您的解决方案中,您也会回到原点。)

答案 1 :(得分:1)

我会这样做:

public interface IChildOf<T> {
    T Parent { get;  set; }
}

public interface IParent<T> {
    List<T> Children { get; set; }
}

//This class handles all of the cases that have both parent and children
public abstract class BaseItem<T1, T2> : IParent<T1>, IChildOf<T2>
{
    public List<T1> Children { get; set; }
    public T2 Parent { get; set; }
}

//This class handles the top level parent
public class ItemA : IParent<ItemB>
{
    public List<ItemB> Children { get;  set; }
}
public class ItemB : BaseItem<ItemC, ItemA>
{
}
public class ItemC : BaseItem<ItemD, ItemB>
{
}
//.... as many intermediates as you like.

//This class handles the bottom level items with no children
public class ItemD : IChildOf<ItemC>
{
    public ItemC Parent { get;  set; }
}

答案 2 :(得分:0)

您可以使用两个通用接口ChildOf<T>IList<T>。这将让您处理最终案例。不幸的是,由于.NET没有多重继承,您将无法共享实现。

或者你可以使用抽象类和标记类型(System.Void是理想的,但我不认为它会编译)最终的情况,并从Parent检查它/ Children属性并抛出异常。

答案 3 :(得分:0)

这似乎不是一个糟糕的想法,虽然说实话,我很想保留最初的解决方案,并忍受铸造,因为它确实增加了相当复杂,没有那么多的好处。 (虽然我必须承认,我会尽可能地用通用代替替换。)

如果你确实想保留它,可以提出几点建议:

  • 将AbstractBase作为接口
  • 为目的做一些不同的事情(例如,两个额外的BaseItems采用父类和子类通用类型)。

显然,第二点只会增加复杂性,这是我不确定它是否值得的另一个原因。

答案 4 :(得分:0)

我没有看到以这种方式做事的问题,因为您似乎有一个特定的层次结构要求顶级项目为ItemA类型,第二级项目为{{1}类型1}}等等。

要解决根节点和叶节点,我可能会定义也来自ItemB的单独类:

AbstractBase