假定现在有SonA和SonB两种树形数据需要返回给前端,SonA和SonB的具体如下:
public class SonA{
public int Id{get;set;}
public int ParentId{get;set;}
public string a{get;set;}
private List<SonA> m_children = new List<SonA>();
public List<SonA> Children
{
get { return m_children; }
set { m_children = value; }
}
}
public class SonB{
public int Id{get;set;}
public int ParentId{get;set;}
public string b{get;set;}
private List<SonB> m_children = new List<SonB>();
public List<SonB> Children
{
get { return m_children; }
set { m_children = value; }
}
}
}
从数据库里取得数据结果为List< SonA> 和List< SonB>,将List里的数据根据parentId整合成树形的数据并不难,但是因为SonA和SonB里有不同的成员变量a,b这就导致我无法通过一个公用的方法来将其整合到树里去,将同样的方法代码复制一遍,改下返回参数和传参自然也可以解决。但是想到以后如果还有不同的树形数据的话,岂不是要无数次复制重写同样的方法。所以我想能不能通过一个方法来实现对这类情况的处理。一般来讲这种通用的方法可以用模板的方式来解决,但是在根据parentId处理放置子节点的时候,势必要用到ParentId,Children等变量。如果直接通过模板的话,定义TreeUtil这样的话,那么在处理的时候t.ParentId这种写法显然编译器就直接报错了。所以可以规定T必须是继承一个拥有这些公共成员变量的父类,或者说基类。
这样的话将Id,ParentId,Children这些公共成员变量放到一个父类Parent里是不是就可以了呢。我放进去之后发现,最终的数据里Children都只有Parent里的字段,而SonA和SonB里独有的a,b直接就被覆盖掉了。这是因为我定义的Children是List< Parent>的,Parent里不存在a,b自然不会在处理之后还存在。只是继承的话,子类可以得到父类的信息,但是父类不能反过来得到子类的信息。
这样就必须要把SonA和SonB传递给Parent,这样Parent里的Children才能自定义成我们需要的数据。于是再次使用模板,将Parent定义成Parent where T:Parent。这样在子类继承Parent的时候可以把自己同时传入。
具体做法如下:
//父类
public class Parent<T> where T : Parent<T>,new(){
public int Id{get;set;}
public int ParentId{get;set;}
private List<T> m_children = new List<T>();
public List<T>Children {
get { return m_children; }
set { m_children =value; }
}
}
//子类A
public class SonA:Parent<SonA>{
public string a{get;set;}
}
//子类B
public class SonB:Parent<SonB>{
public string b{get;set;}
}
//树操作工具类
public static class TreeUtil<T> where T : Parent<T>, new()
{
public static List<T> GetFullTree(List<T> all, Dictionary<int, T> map)
{
all.ForEach(l =>
{
if (l.ParentId != 0)
{
map[l.ParentId].Children.Add(l);
}
});
all.ForEach(l =>
{
l.Children = l.Children.OrderBy(x => x.Sort).ToList();
});
List<T> roots = all.FindAll(x => x.ParentId == 0);
return roots.OrderBy(x => x.Sort).ToList();
}
}
//调用:
List<SonA> all=DB<SonA>.GetAll();
List<SonA> result=TreeUtil<SonA>.GetFullTree(all,all.ToDictionary(x=>x.Id));
通过子类与父类的继承和模板类融合的方法来实现通过一个公共的方法来实现对拥有不同成员变量的SonA和SonB进行了数据的处理。本来在做的时候,还担心这样做是不是会引起继承的互相套娃,导致死循环了。没想到这个想法居然真的行的通。