边看书边做边发挥-图书软件-5

把 Catalogue 类,Chapter 类,Section 类以及两本书的类 FrameworkDesignGuidelinesBook 类和 WpfProgrammingValuables2012Book 类,重写 ToString() 方法,这个方法意义是到字符串,是对象方法,实际上这个方法许多用义是用来返回对象名。让各个类的对象默认显示相关的名称,Catalogue 类的对象都叫目录,Chapter 类和 Section 类的对象由于有字段 name,应该用他们的名字做为对象名。

    public class FrameworkDesignGuidelinesBook : INotifyPropertyChanged
    {
        ...
        public override string ToString()
        {
            return ".NET 设计规范约定、惯用法与模式(第二版)";
        }
        ...
     }

    public class WpfProgrammingValuables2012Book : INotifyPropertyChanged
    {
        ...
        public override string ToString()
        {
            return "WPF 编程宝典 2012";
        }
        ...
    }

    public class Catalogue : ObservableCollection<Chapter>
    {
        ...
        public override string ToString()
        {
            return "目录";
        }
        ...
    }

    public class Chapter : INotifyPropertyChanged
    {
        ...
        public override string ToString()
        {
            return name;
        }
        ...
     }

    public class Section : INotifyPropertyChanged
    {
        ...
        public override string ToString()
        {
            return name;
        }
        ...
     }

然后重新编译并运行控制台项目,这时候只要给 Console.WriteLine() 方法传入对象,他会在内部调用对象的 ToString() 方法,类以的,许多控件需要显示一个对象的名称时,都会调用这个方法,这个方法做为框架纳入基本方法,这也是 object 基类提供了这个方法,object 还有几个静态方法和对象方法,object 类是所有类的顶类,也是所有对象的根

曾初学 C# 语言时,我一直迷茫为什么 object 对象是所有对象的根,为什么不叫所有对象的顶点,最后我得出个人观点是,文化差异造成的,我们一直认为他既然是所有对象的核心对象,就应该像一个金字塔顶一样,站在所有对象的顶端,虽然这么理解也对,他确实是所有对象的源头,和金子塔顶一样形象,可欧美文化可不是这么理解,他们认为 object 对象确实是所有对象的源头,但并不是像金子塔顶一样重要,倒是像一颗树的树根一样,并不会太多关心树根,他深埋入土里,反而关心树枝上的叶,所以就存在一点理解先后的差异,欧美文化从树枝为重点,再往树根下开始理解。而我们则从树根开始,往树枝上开始理解,造成这一差异是因为,教材上说 object 是所有对象的根,让人误以为他很重要,应该从这个重点的对象开始理解,可事实是并非如此,其实他就是一个根,没其他意义,其意义就是为了单根结构而存在。

学习面向对象初期,我还走了一个小弯路,误以为所有的对象都从 object 对象派生,不管是任何类的对象,比如对象a,对象b , 对象c,d,e 等等,他们都共享同一个基对象o,可事件上不是,他们都有自己的基对象o,并不共享,除非他们有依赖关系,这是被类和对象的关系混淆造成,派生是针对类设计的,同样,理解类是对象创建的模板同样重要,写了类并不会马上就能用,需要用关键字 new 一个对象出来,才能操作。更多语言细节相关技术概念参见教材。

回到上面的代码,现在可以在控制台输出对象名了,这里部分目录信息不全。

迭代结果

这里的输出仍然不够直观,目录是一个树层次的视图,应当以层次结构视图输出,那么如何修改类呢?第一层不需要前导空格,第二层前导4个空格,第三层前导8个空格,以此类推。这里面临一个职责分离的问题,应该是把前导空格的代码写在控制台呢还是写在类内,这样控制台直接输出即可。.NET 框架里的 Xml 和 Xaml 的子命名空间的类都把这些代码集成在类内,这是因为这是 Xml 的支持部分。在这里,集成到类内比较好,目录本身就是分层的,但要调用另一个迭代方法,因为已经存在默认的实现了。如果使用默认的迭代方法,绑定到树控件上时,会调用默认迭代方法,加了前导空格,会有更长的前导空白显示在控件上,所以这是个问题,需要一个新的迭代方法。

从 Catalogue 类入手,添加一个新的迭代器 GetEnumeratorTreeView() 方法,他表示按树视图的形式迭代每一项,但是,当迭代 Catalogue 对象时,返回的是 Chapter 对象,而 Chapter 对象包含 Section 对象,Section 对象包含 Section 对象集合,Chapter 对象与 Section 对象的类型不匹配,但他们都是输出都一类型,字符串,所以GetEnumeratorTreeView() 方法的返回类型是 IEnumerable< string>,尽管有些奇怪。

最初我想用一个自定义的迭代方法,加一个递归的辅助方法,完成迭代所有项,包含嵌套的项,而不管嵌套有多少层,却发现出奇的困难,花了太多的时间也没有成功,只好用硬编码三层的方式,如果要四层就需要硬编码四层,显然,这不够灵活。

    public class Catalogue : ObservableCollection<Chapter>
    {
        ...
        public IEnumerable<string> GetEnumeratorTreeView()
        {
            foreach (var chapter in Items)
            {
                var paddingLeft = "    ";//左填充
                yield return chapter.ToString();//首层,章节
                foreach (var section in chapter.Sections)
                {
                    yield return paddingLeft + section.Name;//第二层
                    foreach (var nestSection in section)
                    {
                        //第三层
                        yield return paddingLeft + paddingLeft + nestSection.Name;
                    }
                }
            }
        }
        ...
    }
    public class Section : INotifyPropertyChanged, IEnumerable<Section>
    {
        ...
        public IEnumerator<Section> GetEnumerator()
        {
            return sections.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
        ...
    }

Section 类没有实现任何迭代功能,所以派生 IEnumerable< section> 接口,并实现他。如果 Section 类不实现迭代功能,由 Catalogue 的 GetEnumeratorTreeView() 方法实现也是可以,是否代码更长,但 Section 类失去迭代功能。Section 类包含 Section 集合,所以他自己本身也是一个集合类,只不过管理自己的同类,这样可以形成一个集合中每项也是一个子集合,子集合的项又是一个集合,无限嵌套。

给 FrameworkDesignGuidelinesBook 类的构造函数的 catalogue 字段添加目录信息极度无聊,这可以使用工厂方法来创建,减小部分输入量,这里没有使用,所以并没有完整输入,只输入了一半不到,第三层的信息也只输入第一章。

少部分信息

修改控制台的代码,让迭代器调用自定义迭代方法

        static void Main(string[] args)
        {
            var frameDesGuidlinesBook = new FrameworkDesignGuidelinesBook();
            foreach (var item in frameDesGuidlinesBook.Catalogue.GetEnumeratorTreeView())
            {
                Console.WriteLine(item);
            }
            Console.WriteLine();

            Console.ReadLine();
        }

输出测试

输出上半部分

输出下半部分

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值