是否可以从递归生成的类继承?

时间:2014-11-19 14:16:10

标签: c# inheritance recursion constructor

我有一个进行嵌套分组的类。简化形式如下。

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类中的所有方法没有区别)

2 个答案:

答案 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,但不需要其他方法。