C# 在父子关系中使用泛型

C# 在父子关系中使用泛型,c#,generics,C#,Generics,我有一个抽象类BaseItem,声明如下: public abstract class BaseItem { public BaseItem Parent { get; protected set; } public List<BaseItem> Children = new List<BaseItem>(); public abstract string Function1(); } public abstract class

我有一个抽象类BaseItem,声明如下:

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

    public abstract string Function1();        
}
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>
{
}
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; }
}
公共抽象类BaseItem
{
公共BaseItem父项{get;protected set;}
public List Children=new List();
公共抽象字符串Function1();
}
基本上,我正在尝试实现一种设计,其中每个项都有一个特定类型的父项和一个不同类型的子项

例如,ItemA的子项都是ItemB类型。然后ItemB将有一个ItemA类型的父项和所有ItemC类型的子项。ItemC将有ItemB的父项和ItemD类型的子项

我认为使用泛型来避免不必要的强制转换会更整洁,因为我知道每个继承类的父类和子类将是什么类型。所以我想出了这样的办法:

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

    public abstract string Function1();        
}
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>
{
}
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; }
}
公共抽象类AbstractBase
{
公共抽象字符串Function1();
}
公共抽象类BaseItem:AbstractBase
其中T1:AbstractBase
其中T2:AbstractBase
{
公共T1父项{get;protected set;}
public List Children=new List();
}
公共类ItemA:BaseItem
{
}
公共类ItemB:BaseItem
{
}
公共类ItemC:BaseItem
{
}
公共类ItemD:BaseItem
{
}
所以有两件事。 1.这个设计好吗?有没有更简单/更好的方法?我真的不喜欢为了能够使用泛型而使用第二个抽象基类。
2.如果我保留了这个,处理末端的最好方法是什么?(即ItemA在我的实际问题域中没有父级,但它需要一个父级来编译。ItemD没有子级,但我需要给它一些东西)

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


或者,您可以使用抽象类和标记类型(
System.Void
将是理想的选择,但我认为它不会编译)作为结束案例,并从
父类
/
子类
属性检查它并抛出异常。

这似乎不是一个太坏的主意,虽然说实话,我还是想保留原来的解决方案,并忍受演员阵容,因为它确实增加了相当多的复杂性,但并没有带来太多的好处。(尽管我必须承认,只要有可能,我会尝试用泛型替换casting)

如果您确实想保留它,有几点建议:

  • 将AbstractBase作为接口
  • 对端点执行不同的操作(例如,两个额外的BaseItem采用父泛型类型和子泛型类型)

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

如果我理解正确,你是说
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; }
}
公共抽象类AbstractBase
{
公共抽象字符串Function1();
}
公共类ItemA:AbstractBase
{
public List Children=new List();
}
公共类ItemB:AbstractBase
{
public ItemA父项{get;protected set;}
public List Children=new List();
}
公共类ItemC:AbstractBase
{
public ItemB父项{get;protected set;}
public List Children=new List();
}
公共类ItemD:AbstractBase
{
public ItemC父项{get;protected set;}
}

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

我会这样做:

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

    public abstract string Function1();        
}
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>
{
}
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; }
}
公共接口IChildOf{
T父{get;set;}
}
公共接口IParent{
列出子项{get;set;}
}
//此类处理同时具有父级和子级的所有情况
公共抽象类BaseItem:IParent,IChildOf
{
公共列表子项{get;set;}
公共T2父项{get;set;}
}
//此类处理顶级父级
公共类项目A:IParent
{
公共列表子项{get;set;}
}
公共类ItemB:BaseItem
{
}
公共类ItemC:BaseItem
{
}
//.... 你喜欢多少中间产物就有多少。
//此类处理没有子级的底层项
公共类项目D:IChildOf
{
public ItemC父项{get;set;}
}

我不认为这样做有什么问题,因为您似乎有一个特定的继承权,要求顶级项目的类型为
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>
{
}
公共抽象类RootItem:AbstractBase
其中T2:AbstractBase
{
public List Children=new List();
}
公共抽象类leaftItem:AbstractBase
其中T1:AbstractBase
{
公共T1父项{get;protected set;}
}
公共类ItemA:RootItem
{
}
公共类ItemB:BaseItem
{
}
公共类ItemC:BaseItem
{
}
公共类ItemD:leaftItem
{
}

这个问题让我想使用FORTRAN。您的代码示例有
公共类ItemC:BaseItem
,但您可能是指
公共类ItemC:BaseItem
。您始终可以使用IoC/DI插入两个接口的默认实现接受您的答案,因为最终,无论我用哪种方式,让泛型工作都是一个很大的开销,但没有什么好处。