2010-08-02 90 views
7

我有一个抽象类BaseItem声明如下:在父子关系中使用泛型

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

    public abstract string Function1();   
} 

基本上,我试图实现设计,其中每个项目有一个家长,这将是一种特定类型的和将是不同类型的儿童。

例如,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> 
{ 
} 

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

+0

这个问题让我想使用FORTRAN。 – iandisme 2010-08-02 15:40:25

+0

您的代码示例具有'公共类ItemC:BaseItem ',但您可能是指公共类ItemC:BaseItem '。 – 2010-08-02 17:05:30

回答

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中实现的所有其他常用功能。 (当然,除非该功能需要访问父母/子女 - 但是即使在您的解决方案中,您也可以回到原来的位置。)

+0

接受您的答案是因为最终,要使泛型能够正常工作,无论我采用哪种方式进行操作都会产生大量开销,但收效甚微。 – 2010-08-03 13:18:51

0

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

另外,您可以使用抽象类和标识类型(System.Void将是理想的,但我不认为它会编译)为结束的情况下,从Parent/Children性能检查,并抛出一个异常。

+0

您可以随时使用IoC/DI来注入两个接口的默认实现。 – STW 2010-08-02 15:47:24

0

这似乎不是太糟糕的想法,但说实话我会试图保持原来的解决方案,并与演员混在一起,因为它确实增加了一点复杂性,没有那么多好处。 (尽管我必须承认我会尽可能地用泛型替换铸件)。

如果你确实想保持它,一对夫妇的建议:

  • 有AbstractBase作为接口
  • 做一些事情的结束(这需要父母和孩子一般的如两个额外BaseItems不同类型)。

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

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; } 
} 
0

我看不出这样做,让一个问题,因为你似乎有需要顶级项目是类型的特定层次结构ItemA,第二级项是ItemB类型等

为了解决根和叶节点,我可能限定单独的类也从AbstractBase导出:

public abstract class RootItem<T2> : AbstractBase 
    where T2 : AbstractBase 
{ 
    public List<T2> Children = new List<T2>(); 
} 

public abstract class LeafItem<T1> : AbstractBase 
    where T1 : AbstractBase 
{ 
    public T1 Parent { get; protected set; } 
} 

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