zoukankan      html  css  js  c++  java
  • 【转】编写高质量代码改善C#程序的157个建议——建议23:避免将List<T>作为自定义集合类的基类

    建议23:避免将List<T>作为自定义集合类的基类

    如果要实现一个自定义的集合类,不应该以一个FCL集合类为基类,反而应扩展相应的泛型接口。FCL结合类应该以组合的形式包含至自定义的集合类,需要扩展的泛型接口通常是IEnumerable<T>和ICollection<T>(或ICollection<T>的子接口,如IList<T>),前者规范了集合类的迭代功能,后者规范了一个集合通常会有的操作。

    一般的情况下,下面两个实现的集合类都能完成默认的需求:

    class Employees1 : List<Employee>
    class Employees2 : IEnumerable<Employee>, ICollection<Employee>

    不过,List<T>基本上没有提供可供子类使用的protected成员(从object中继承的Finalize和MemberwiseClone方法除外),所以继承List<T>并没有带来任何继承上的优势,反而丧失了面向接口编程的灵活性。稍加不注意,隐含的Bug就会接踵而至。

    以Employees1为例,如果要在Add方法中加入某些需求方面的变化,比如,为名字添加一个后缀“Changed!",但是客户端的开发人员也许已经习惯了面向接口编程的方式,他在为集合添加一个元素是使用了如下的语法:

            static void Main(string[] args)
            {
                Employees1 employees1 = new Employees1() 
                {
                    new Employee(){ Name = "Mike" },
                    new Employee(){ Name = "Rose" }
                };
                IList<Employee> employees = employees1;
                employees.Add(new Employee() { Name = "Steve" });
                foreach (var item in employees1)
                {
                    Console.WriteLine(item.Name);
                }
            }
    
            class Employee
            {
                public string Name { get; set; }
            }
    
            class Employees1 : List<Employee>
            {
                public new void Add(Employee item)
                {
                    item.Name += " Changed!";
                    base.Add(item);
                }
            }

    于是,代码的实际输出会偏离集合类设计者的设想。代码输出为:

    Mike Changed!
    Rose Changed!
    Steve

    要纠正这类行为,应该采用Employees2的方式:

            static void Main(string[] args)
            {
                Employees2 employees2 = new Employees2() 
                {
                    new Employee(){ Name = "Mike" },
                    new Employee(){ Name = "Rose" }
                };
                ICollection<Employee> employees = employees2;
                employees.Add(new Employee() { Name = "Steve" });
                foreach (var item in employees2)
                {
                    Console.WriteLine(item.Name);
                }
            }
    
            class Employees2 : IEnumerable<Employee>, ICollection<Employee>
            {
                List<Employee> items = new List<Employee>();
    
                #region IEnumerable<Employee> 成员
    
                public IEnumerator<Employee> GetEnumerator()
                {
                    return items.GetEnumerator();
                }
    
                #endregion
    
                #region ICollection<Employee> 成员
    
                public void Add(Employee item)
                {
                    item.Name += " Changed!";
                    items.Add(item);
                }
    
                //省略
    
                #endregion
            }

    输出结果为:

    Mike Changed!
    Rose Changed!
    Steve Changed!

    转自:《编写高质量代码改善C#程序的157个建议》陆敏技

  • 相关阅读:
    Python、Lua和Ruby比较——脚本语言大P.K.
    vim 设置默认显示行号
    C语言
    How To Add Swap on Ubuntu 14.04
    How To Install Apache Kafka on Ubuntu 14.04
    php的错误和异常处理
    md5sum
    大牛的博客
    【转】4G手机打电话为什么会断网 4G上网和通话不能并存原因分析
    【转】女人最想要的是什么
  • 原文地址:https://www.cnblogs.com/farmer-y/p/7930018.html
Copyright © 2011-2022 走看看