让所有孩子都在树上

时间:2018-09-03 14:15:36

标签: c#

有一个存储元素树的类。子元素存储在

public List<BaseTreeData> Child { get; set; }

我想将此树显示为所有元素的“平面”(线性)列表。在将类划分为两个类(基本类和继承类)之后, GetChildren 方法会生成有关类型不匹配的错误。很有可能一切都是合乎逻辑的,但是如何解决呢?

  

错误CS1503参数1:无法从“ ConsoleApplication1.BaseTreeData”转换为“ ConsoleApplication1.TreeData”

namespace ConsoleApplication1
{
    class Program
    {        
        static void Main(string[] args)
        {
            var data = new List<TreeData>();
            for (int i = 0; i < 5; i++)
            {
                var item = new TreeData() { Name = i.ToString() };
                for (int j = 0; j < 3; j++)
                {
                    var number = (i + 1) * 10 + j;
                    item.Child.Add(new TreeData() { ID = number, Name = number.ToString(), Parent = item });                    
                }
                data.Add(item);
            }

            foreach (var item in data.SelectMany(x => GetChildren(x)))
            {
                Console.WriteLine(item.ID + " " + item.Name + " " + item.IsChecked);
            }
        }

        static IEnumerable<TreeData> GetChildren(TreeData d)
        {
            return new[] { d }.Concat(d.Child).SelectMany(x => GetChildren(x));
        }
    }

    class BaseTreeData
    {
        public bool IsChecked { get; set; }
        public BaseTreeData Parent { get; set; }
        public List<BaseTreeData> Child { get; set; }

        public BaseTreeData()
        {
            Child = new List<BaseTreeData>();
        }
    }

    class TreeData : BaseTreeData
    {
        public int ID { get; set; }
        public string Name { get; set; }
    }
}

2 个答案:

答案 0 :(得分:0)

根据您的BaseTreeData类定义,childparent将始终返回基类型。您可以使用泛型来解决此问题,以使Children与父类的类型相同:

class BaseTreeData<T> where T : BaseTreeData<T>
{
    public bool IsChecked { get; set; }
    public T Parent { get; set; }
    public List<T> Children { get; set; }

    public BaseTreeData()
    {
        Children = new List<T>();
    }

    public IEnumerable<T> GetAncestors()
    {
        if (Parent == null)
            yield break;

        T relative = Parent;
        while (relative != null)
        {
            yield return relative;
            relative = relative.Parent;
        }
    }

    public IEnumerable<T> GetDescendants()
    {
        var nodes = new Stack<T>();
        nodes.Push(this as T);

        while (nodes.Any())
        {
            var current = nodes.Pop();
            yield return current;

            foreach (var childNode in current.Children)
                nodes.Push(childNode);
        }
    }
}

class TreeData : BaseTreeData<TreeData>
{
    public int ID { get; set; }
    public string Name { get; set; }
}

答案 1 :(得分:-1)

您的基类属性Child的类型为List<BaseTreeData>,但是您正在尝试调用静态方法GetChildren,该方法需要类型为TreeData的对象。您实质上是在尝试向上投射对象。编译器将如何知道用什么填充IDName

一种更优雅的方法是让每个类决定其字符串表示形式。因为您只可以使用基类的GetChildren属性,所以无需使用Child方法:

foreach (var item in data.SelectMany(x => x.Child))
{
    Console.WriteLine(item.ToString());
}

然后,您重写ToString实现,以便基类提供其值,而派生类基于此实现:

class BaseTreeData
{
    //Other stuff here
    //...
    public override string ToString()
    {
        return IsChecked.ToString();
    }
}

class TreeData : BaseTreeData
{
    //Other stuff here
    //...
    public override string ToString()
    {
        var format = "{0} {1} {2}";
        var stringRepresentation = string.Format(format, ID, Name, base.ToString());
        return stringRepresentation;
    }
}

在参数中注意对base.ToString()的调用。

输出:

  

10 10错误

     

11 11错误