【读书笔记】编写高质量代码改善C# 建议16-20

16、元素可变的情况下不应该使用数组

废话

而且使用数组时不能指定过大的长度,这会使回收时效率特别低。当内存超过85KB时,就是数组的长度过长了

17、多数情况下使用foreach进行循环遍历

foreach用到了迭代器,下面是手动实现的简单迭代器

interface IMyEnumerator
{
    bool MoveNext();
    object Current { get; }
}

interface IMyEnumerable
{
    IMyEnumerator GetEnumerator();
    int Count { get; }
}

class MyList : IMyEnumerable
{

    object[] items = new object[10];
    IMyEnumerator myEnumerator;

    public object this[int i]
    {
        get { return items[i]; }
        set { items[i] = value; }
    }

    public int Count
    {
        get { return items.Length; }
    }

    public IMyEnumerator GetEnumerator()
    {
        if (myEnumerator == null)
            myEnumerator = new MyEnumerator(this);
        return myEnumerator;
    }
}

class MyEnumerator : IMyEnumerator
{
    int index = 0;
    MyList myList;
    public MyEnumerator(MyList myList)
    {
        this.myList = myList;
    }

    public bool MoveNext()
    {
        if(index +1 > myList.Count)
        {
            index = 1;
            return false;
        }
        else
        {
            index++;
            return true;
        }
    }

    public object Current
    {
        get { return myList[index - 1]; }
    }
}

下面是使用系统的 IEnumerator IEnumerable   ICollection继承自IEnumerable   

ICollection<int> list = new List<int>();
list.Add(4);
list.Add(5);
list.Add(2);
list.Add(6);
IEnumerator<int> enumerator = list.GetEnumerator();
            
while (enumerator.MoveNext())
{
    Console.WriteLine(enumerator.Current);
}

这个是foreach的反编译代码

可以看出跟上面我们自己实现的基本一致,但是多了一个自动调用Dispose()

18、foreach不能代替for

在foreach中不能更改集合的内容,因为IEnumerator 内部维护了一个版本号,就上面一段代码来分析

如果我们在已经创建过的IEnumerator后面再修改list的内容,然后使用IEnumerator,list的版本号就会跟IEnumerator里面维护的版本号不同,系统就会报错,下面是IEnumerator的MoveNext() 实现,可以看到IEnumerator里面维护着一个数组,并且每次调用时都会判断版本号是否相同

但是for循环不会产生这种情况,for只是简单的索引取值

19、使用有效的对象和集合初始化

对象初始化:

Person p1 = new Peroson() { Name = "Rose" , Age = 21 };

集合初始化

List<Person> lists = new List<Person>()
{
    new Person(){Name = "Rose",Age = 22},
    new Person(){Name = "Jack",Age = 21},
    new Person(){Name = "Ju",Age = 22}
};

不过初始化的设定绝不仅仅是为了对象和集合初始化的方便,它更重要的作用是为LINQ查询中的匿名类型进行属性的初始化。由于LINQ查询返回的集合中匿名类型的属性都是只读的,如果需要为匿名类型属性赋值,或者增加属性,只能通过初始化设定项来进行

List<Person> lists = new List<Person>()
{
    new Person(){Name = "Rose",Age = 22},
    new Person(){Name = "Jack",Age = 21},
    new Person(){Name = "Ju",Age = 22}
};

//通过计算age的大小来获得新的属性AgeScope 并存入到一个匿名类型中
var temp = from p in lists select new { p.Name, AgeScope = p.Age > 21 ? "Old" : "Young" };

foreach (var item in temp)
{
    Console.WriteLine(item.Name + ":" + item.AgeScope);
}

20、使用泛型集合代替非泛型集合

主要就是使用List<T> 代替ArrayList 

ArrayList 不仅需要装箱拆箱,而且编译器并不会检查类型

猜你喜欢

转载自blog.csdn.net/qq_33413868/article/details/81449887