zoukankan      html  css  js  c++  java
  • 编写高质量代码改善C#程序的157个建议——建议25:谨慎集合属性的可写操作

    建议25:谨慎集合属性的可写操作

    如果类型的属性中有集合属性,那么应该保证属性对象是由类型本身产生的。如果将属性设置为可写,则会增加抛出异常的几率。一般情况下,如果集合属性没有值,则它返回的Count等于0,而不是集合属性的值为null。下面的代码将产生一个NullReferenceException异常:

        class Program
        {
            static List<Student> listStudent = new List<Student>()
                {
                    new Student(){ Name = "Mike", Age = 1},
                    new Student(){ Name = "Rose", Age = 2}
                };
    
            static void Main(string[] args)
            {
                StudentTeamA teamA = new StudentTeamA();
                Thread t1 = new Thread(() =>
                {
                    teamA.Students = listStudent;
                    Thread.Sleep(3000);
                    Console.WriteLine(listStudent.Count); //模拟对
                    //集合属性进行一些运算
                });
                t1.Start();
                Thread t2 = new Thread(() =>
                {
                    listStudent = null;   //模拟在别的地方对list1而
                    //不是属性本身赋值为null
                });
                t2.Start();
            }
        }
    
        class Student
        {
            public string Name { get; set; }
            public int Age { get; set; }
        }
    
        class StudentTeamA
        {
            public List<Student> Students { get; set; }
        }

    上面代码的问题是:线程t1模拟将对类型StudentTeamA的Students属性进行赋值,它是一个可读/可写的属性。由于集合属性是一个引用类型,而当前针对该属性对象的引用却又两个,即集合本身和调用者的类型变量listStudent,线程t2也许是另一个程序员写的,但他看到的只有listStudent,结果,针对listStudent的修改hi直接影响到另一个工作线程的对象。在例子中,我们将listStudent赋值为null,模拟在StudentTeamA(或者说工作线程t1)不知情的情况下使得集合属性变为null。接着,线程t1模拟针对Students属性进行若干操作,导致抛出异常。

    下面的StudentTeamA版本是一个改进过的版本。首先,将类型的集合属性设置为只读;其次,集合对象由类型自身创建,这保证了集合属性永远只有一个引用:

        class Program
        {
            static List<Student> listStudent = new List<Student>()
                {
                    new Student(){ Name = "Mike", Age = 1},
                    new Student(){ Name = "Rose", Age = 2}
                };
            
            static void Main(string[] args)
            {
                StudentTeamA teamA2 = new StudentTeamA();
                teamA2.Students.Add(new Student() { Name = "Steve", Age = 3 });
                teamA2.Students.AddRange(listStudent);
                Console.WriteLine(teamA2.Students.Count);
                //也可以像下面这样实现
                StudentTeamA teamA3 = new StudentTeamA(listStudent);
                Console.WriteLine(teamA3.Students.Count);
            }
    
        class Student
        {
            public string Name { get; set; }
            public int Age { get; set; }
        }
    
        class StudentTeamA
        {
            public List<Student> Students { get; private set; }
    
            public StudentTeamA()
            {
                Students = new List<Student>();
            }
    
            public StudentTeamA(IEnumerable<Student> studentList)
                : this()
            {
                Students.AddRange(studentList);
            }
        }

    在改进版本的StudentTeamA中尝试对属性Students进行赋值:

     teamA.Students = listStudent;

    将导致编译通不过。

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

  • 相关阅读:
    如何退出Vi编辑状态
    iOS开发第三方工具——MBProgressHUD
    iOS开发第三方工具——AFNetworking
    iOS开发第三方工具——JSONKit
    iOS开发第三方工具——SSToolkit
    TestFlight工具的使用
    Block 的循环引用
    在 iOS 9 中使用 UIStackView 的总结
    说说视图层架构
    iOS开发技巧(2)
  • 原文地址:https://www.cnblogs.com/jesselzj/p/4731270.html
Copyright © 2011-2022 走看看