我有一个进行嵌套分组的类。简化形式如下。
public class Group
{
public readonly object Key;
public readonly IEnumerable<Group> Groups;
public readonly IEnumerable<DataRow> Drs;
public Group(object key, IEnumerable<DataRow> source, List<string> columnList)
{
Key = key;
if (columnList.Count == 0)
Drs = source;
else
{
string firstColumn = columnList.First();
List<string> restOfColumns = columnList.Skip(1).ToList();
Groups = source.GroupBy(dr => dr[firstColumn])
.Select(g => new Group(g.Key, g, restOfColumns));
}
}
}
在某种程度上这很好。但有时候我需要更多这个类的属性(和方法)。同时我不想将这些属性添加到这个类中,因为它会破坏简单性,大多数用法都不会对这些属性感兴趣。出于这个原因,我尝试从这个类继承。
public class SpecialGroup:Group
{
public SpecialGroup(object key, IEnumerable<DataRow> source, List<string> columnList)
: base(key, source, columnList)
{
}
public void DoSomething()
{
// do something
}
}
但这次SpecialGroup
没有被递归生成(如预期的那样)。只有第一个主要组是SpecialGroup
,嵌套组都是Group
。
我可以通过某种方式从Group
继承而且仍然有新类型的递归吗?
(请不要使用扩展方法,因为它与编写Group
类中的所有方法没有区别)
答案 0 :(得分:4)
您可以更改组多态的创建。例如:
public class Group
{
public readonly object Key;
public readonly IEnumerable<Group> Groups;
public readonly IEnumerable<DataRow> Drs;
public Group(object key, IEnumerable<DataRow> source, List<string> columnList)
{
Key = key;
if (columnList.Count == 0)
Drs = source;
else
{
string firstColumn = columnList.First();
List<string> restOfColumns = columnList.Skip(1).ToList();
Groups = source.GroupBy(dr => dr[firstColumn])
.Select(g => CreateGroup(g.Key, g, restOfColumns));
}
}
protected virtual Group CreateGroup(object key, IEnumerable<DataRow> source, List<string> columnList)
{
return new Group(key, source, columnList)
}
}
然后在SpecialGroup
覆盖它以返回SpecialGroup
。
public class SpecialGroup:Group
{
public SpecialGroup(object key, IEnumerable<DataRow> source, List<string> columnList)
: base(key, source, columnList)
{
}
public void DoSomething()
{
// do something
}
protected override Group CreateGroup(object key, IEnumerable<DataRow> source, List<string> columnList)
{
return new SpecialGroup(key, source, columnList)
}
}
这样,如果您的根组的类型为SpecialGroup
,则其子项的类型为SpecialGroup
,否则为Group
。
答案 1 :(得分:1)
我想使用泛型提供稍微不同的解决方案。问题是C#
不允许为泛型类型 T 调用非默认构造函数,所以我不得不求助于某些反思。
using System.Reflection;
public class Group<T> where T : Group<T>
{
public readonly object Key;
public readonly IEnumerable<T> Groups;
public readonly IEnumerable<DataRow> Drs;
public Group(object key, IEnumerable<DataRow> source, List<string> columnList)
{
Key=key;
if(columnList.Count==0)
Drs=source;
else
{
string firstColumn=columnList.First();
List<string> restOfColumns=columnList.Skip(1).ToList();
Groups=source.GroupBy(dr => dr[firstColumn])
.Select(g => Factory(g.Key, g, restOfColumns));
}
}
static ConstructorInfo ctor; //store constructor for type T
static T Factory(object key, IEnumerable<DataRow> source, List<string> columnList)
{
if(ctor==null)
{
// if constructor not found yet, assign it
ctor=typeof(T).GetConstructor(new Type[] {
typeof(object),
typeof(IEnumerable<DataRow>),
typeof(List<string>)});
if(ctor==null)
{
throw new MissingMethodException("Could not find appropriate constructor");
}
}
// invoke constructor to create a new T
return ctor.Invoke(new object[] { key, source, columnList }) as T;
}
}
public class SpecialGroup : Group<SpecialGroup>
{
public SpecialGroup(object key, IEnumerable<DataRow> source, List<string> columnList)
: base(key, source, columnList) { }
void DoSomething() { }
}
请注意,您无法再创建Group<T>
的实例。对于基类,您需要像class BaseGroup : Group<BaseGroup> { }
一样定义SpecialGroup
,但不需要其他方法。