14.集合

1.System.Collections命名空间中的几个接口

1)IEnumerable可迭代集合中的项;

2)ICollection(继承于IEnumerable)可以获取集合中项的个数,并把项复制到一个简单的数组中;

3)IList(继承于IEnumerable和ICollection)提供了集合的项列表,允许访问这些项,并提供一些与项相关的基本功能;

4)IDictionary(继承于IEnumerable和ICollection)类似IList,但提供了通过键值(而不是索引)访问项的列表;

以上几个接口提供了基本的集合功能。System.Array类实现了IEnumerable、ICollection和IList接口,但不支持IList的一些更高级的功能,它表示大小固定的项列表。C#中的数组是System.Array类的实例。

2.使用数组实现扑克牌集合

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Deck d = new Deck();
            for (int i = 0; i < 52; i++)
            {
                Console.Write(d.GetCard(i));
                
            }
            Console.WriteLine();
            Console.WriteLine();
            d.Shuffle();

            for (int i = 0; i < 52; i++)
            {
                Console.Write(d.GetCard(i));
                
            }
            d.GetCard(53);
            Console.WriteLine();
            Console.WriteLine();
                Console.ReadLine();
        }
    }

   

    class Card
    {
        private readonly Suit suit;
        private readonly Rank rank;

        public Card(Suit suit,Rank rank)
        {
            this.suit = suit;
            this.rank = rank;
        }

        public override string ToString()
        {
            return "The "+rank .ToString()+" of "+ suit.ToString()+" s";
        }
    }

    /// <summary>
    /// 使用数组实现集合Deck,缺点是集合的大小是固定的
    /// </summary>
    class Deck {
        private Card[] Cars;

        public Deck()
        {
            Cars = new Card[52];
            for (int suitVal = 0; suitVal < 4; suitVal++)
            {
                for (int rankVal = 1; rankVal <= 13; rankVal++)
                {
                    Cars[suitVal * 13 + rankVal - 1] = new Card((Suit)suitVal, (Rank)rankVal);
                }
            }
        }

        public Card GetCard(int cardNum)
        {
            if (cardNum >= 0 && cardNum <= 51)
                return Cars[cardNum];
            else
                throw new ArgumentOutOfRangeException("cardNum", cardNum, "Value must between 0 and 51.");
        }

        public void Shuffle()
        {
            Random sourceGen = new Random();
            Card[] newCards = new Card[52];
            bool[] assigned = new bool[52];
            for (int i = 0; i < 52; i++)
            {
                int destCard = 0;
                bool foundCard = false;
                while (!foundCard)
                {
                    destCard = sourceGen.Next(52);
                    if (assigned[destCard] == false)
                        foundCard = true;
                }
                assigned[destCard] = true;
                Cars[destCard]=newCards[i];
            }
            newCards.CopyTo(Cars ,0);
        }


    }

    public enum Suit
    { 
        Club,//梅花
        Diamond,//方块
        Heart,//红桃
        Spade//黑桃

    }

    public enum Rank
    { 
        Ace=1,//幺点
        Deuce,//两点
        Three,
        Four,
        Fine,
        Six,
        Seven,
        Eight,
        Nine,
        Ten,
        Jack,
        Queen,
        King

    }
}
View Code

数组实现集合的缺点:集合大小是固定的,不能改变。

3.使用System.Collections.ArrayList实现扑克牌集合

ArrayList也实现了IEnumerable、ICollection和IList接口,但比System.Array更复杂,和System.Array相比,它的大小是不固定的。

 abstract class Animal
    {
        protected string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        public Animal()
        {
            name = "The animal has no name.";
        }

        public Animal(string newName)
        {
            name = newName;
        }

        public void Feed()
        {
            Console.WriteLine("{0}has been fed.", name);
        }
    }

    class Cow : Animal
    {
        public void Milk()
        {
            Console.WriteLine("{0}has been milked.", name);
        }

        public Cow(string newName)
            : base(newName)
        {

        }
    }

    class Chicken : Animal {
        public void LagEgg()
        {
            Console.WriteLine("{0}has lag en egg.", name);
        }

        public Chicken(string newName)
            : base(newName)
        { 
            
        }
    }
View Code
class Program
    {

        static void Main(string[] args)
        {
            Animal[] animalArray = new Animal[2];
            Cow myCow1 = new Cow("Deirdre");
            animalArray[0] = myCow1;
            animalArray[1] = new Chicken("Ken");

            foreach (Animal myAnimal in animalArray)
            {
                Console.WriteLine("New {0} object added to collection,Name= {1}",myAnimal.ToString(),myAnimal.Name);
            }

            Console.WriteLine("Array collection contains {0} objects", animalArray.Length);

            animalArray[0].Feed();
            ((Chicken)animalArray[1]).LagEgg();

            ArrayList animalArrayList = new ArrayList();
            Cow myCow2 = new Cow("Hayley");
            animalArrayList.Add(myCow2);
            animalArrayList.Add(new Chicken("Roy"));

            foreach (Animal myAnimal in animalArrayList)
            {
                Console.WriteLine("New {0} object added to ArrayList collection,Name = {1}", myAnimal.ToString(), myAnimal.Name);
            }
            Console.WriteLine("ArrayList collection contains {0} objects", animalArrayList.Count);

            ((Animal)animalArrayList[0]).Feed();
            ((Chicken)(animalArrayList[1])).LagEgg();

            animalArrayList.RemoveAt(0);
            animalArrayList.AddRange(animalArray);//后加入的排在前面
            ((Cow)animalArrayList[0]).Milk();

            Console.WriteLine("The animal called {0} is at index {1}", myCow1.Name, animalArrayList.IndexOf(myCow1));
            myCow1.Name = "Janice";
            Console.WriteLine("The animal is now called {0}", ((Animal)animalArrayList[0]).Name);

            Console.ReadLine();
        }
       
    }
View Code

数组和ArrayList的比较:

数组需要用固定大小的常量值来初始化,初始化后大小是固定的,ArrayList有两个构造函数,另一个构造函数可以设置列变的初始大小,如果集合的项个数超过了这个值就增加一倍。ArrayList的大小是变化的。

Animal[] animalArray = new Animal[2];

ArrayList animalArrayList = new ArrayList();

数组初始化之后,它的项并没有初始化,需要按照下标给每项分别初始化。ArrayList不能像数组那样初始化,因为他的项还没有添加,需要用Add方法才会添加一个新项,并为这个新项分配内存空间。

            Cow myCow1 = new Cow("Deirdre");
            animalArray[0] = myCow1;
            animalArray[1] = new Chicken("Ken");    

            Cow myCow2 = new Cow("Hayley");
            animalArrayList.Add(myCow2);
            animalArrayList.Add(new Chicken("Roy"));

数组个数使用Length属性,ArrayList使用Count属性

数组是强类型集合,ArrayList是System.Object的集合,使用时需要把对象强制转换为对应的类型

            animalArray[0].Feed();
            ((Chicken)animalArray[1]).LagEgg();

            ((Animal)animalArrayList[0]).Feed();
            ((Chicken)(animalArrayList[1])).LagEgg();

ArrayList功能更多,比如RemoveAt,Remove,还可以使用AddRange方法把支持ICollection接口的对象加到集合中

4.使用CollectionBase建立集合

定制集合可以创建强类型化的集合,可以完全自己写代码创建集合,也可以通过继承现有类创建集合,一般通过继承集合底层的类创建集合。

CollectionBase类实现了IEnumerable、ICollection和IList接口,但是只提供了一些实现代码,比如IList的Clear()和RemoveAt,以及ICollection的Count属性,需要用到其他功能需要自己实现。

abstract class Animal
    {
        protected string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        public Animal()
        {
            name = "The animal has no name.";
        }

        public Animal(string newName)
        {
            name = newName;
        }

        public void Feed()
        {
            Console.WriteLine("{0}has been fed.", name);
        }
    }

class Animals : CollectionBase
    { 
        public void Add(Animal newAnimal)
        {
            List.Add(newAnimal);
        }

        public void Remove(Animal oldAnimal)
        {
            List.Remove(oldAnimal);
        }

        /// <summary>
        /// 索引符只能访问已添加的项,超过Count-1会产生超出索引异常
        /// </summary>
        /// <param name="animalIndex"></param>
        /// <returns></returns>
        public Animal this[int animalIndex]
        {
            get { return (Animal)List[animalIndex]; }
            set { List[animalIndex] = value; }
        }
    }
View Code
    class Program
    {

        static void Main(string[] args)
        {
            Animals animalCollection = new Animals();
            Cow myCow1 = new Cow("Deirdre");
            animalCollection.Add(myCow1);
            animalCollection.Add(new Chicken("Ken"));

            foreach (Animal myAnimal in animalCollection)
            {
                Console.WriteLine("New {0} object added to collection,Name= {1}",myAnimal.ToString(),myAnimal.Name);
            }

            Console.WriteLine(animalCollection[1].Name);
            Console.ReadLine();
        }
       
    }

5.使用DictionaryBase创建集合

DictionaryBase可以创建键值对集合,通过关键字访问项。DictionaryBase实现了IDictionary,IEnumerable、ICollection接口。和CollectionBase一样它提供了部分功能,如Clear()、和Count,但没有RemoveAt()因为它是IList接口上的功能,但是IDictionary接口有Remove功能,可以使用这个实现Remove功能。

abstract class Animal
    {
        protected string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        public Animal()
        {
            name = "The animal has no name.";
        }

        public Animal(string newName)
        {
            name = newName;
        }

        public void Feed()
        {
            Console.WriteLine("{0}has been fed.", name);
        }
    }

    class Animals :DictionaryBase
    { 
        public void Add(string newId, Animal newAnimal)
        {
            Dictionary.Add(newId, newAnimal);
        }

        public void Remove(string oldId,Animal oldAnimal)
        {
            Dictionary.Remove(oldId);
        }

        /// <summary>
        /// 索引符只能访问已添加的项,超过Count-1会产生超出索引异常
        /// </summary>
        /// <param name="animalIndex"></param>
        /// <returns></returns>
        public Animal this[string key]
        {
            get { return (Animal)Dictionary[key]; }
            set { Dictionary[key] = value; }
        }
    }

    class Program
    {

        static void Main(string[] args)
        {
            Animals animalCollection = new Animals();
            Cow myCow1 = new Cow("Deirdre");
            animalCollection.Add("111",myCow1);
            animalCollection.Add("222",new Chicken("Ken"));

            foreach (DictionaryEntry d in animalCollection)
            {
                Console.WriteLine("New {0} object added to collection,Name= {1}",d.Value.ToString(),((Animal)d.Value).Name);
            }
            Console.WriteLine(animalCollection["111"].Name);
            Console.ReadLine();
        }
       
    }
View Code

6.迭代器

我们知道IEnumerable接口是负责实现foreach循环的,假如循环的方式并不是我们想要的就需要重写循环方式,但是重写循环方式并不是很简单。我们看下在foreach循环中究竟干了什么。

在foreach循环中,迭代集合collectionObject的过程如下:

1)调用collectionObject.GetEnumerator(),返回一个IEnumerator引用。这个可以从IEnumerable接口的实现代码获取,但这是可选的,可以在实现IEnumerable接口的情况下创建一个GetEnumerator()用于循环(即下面说的迭代器);

2)调用IEnumerator的MoveNext方法;

3)如果MoveNext方法返回true,调用IEnumerator的Current获取对象的一个引用,用于foreach循环;

4)重复上面两步直到循环结束。

由此可以看出重写foreach循环方式需要重写几个方法(GetEnumerator(),MoveNext()等),跟踪索引,维护Current属性,以及执行其他一些操作,这需要做很多工作。比较简单的替代方法是使用迭代器。使用迭代器可以有效的在后台生成许多代码,不用我们去实现那么多。

迭代器是一个代码块,它按顺序提供了要在foreach循环中用到的值

    class Program
    {

        static void Main(string[] args)
        {
            foreach(string s in SimpleList())
            {
                Console.WriteLine(s);
            }
            Console.ReadLine();
        }

        static IEnumerable SimpleList()
        {
            yield return "string 1";
            yield return "string 2";
            yield return "string 3";
        }
       
    }

以上是一个迭代器的例子,在迭代器中使用yield关键字提供在foreach循环中用到的值。迭代器的返回类型有IEnumerable和IEnumerator两种类型,这两个类型使用的场合是:

1)如果要迭代一个类可以使用GetEnumerator方法,其返回类型是IEnumerator;

2) 如果要迭代一个类成员,比如一个方法,使用IEnumerable。

使用迭代器重写Animals foreach循环

abstract class Animal
    {
        protected string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        public Animal()
        {
            name = "The animal has no name.";
        }

        public Animal(string newName)
        {
            name = newName;
        }

        public void Feed()
        {
            Console.WriteLine("{0}has been fed.", name);
        }
    }

    class Cow : Animal
    {
        public void Milk()
        {
            Console.WriteLine("{0}has been milked.", name);
        }

        public Cow(string newName)
            : base(newName)
        {

        }
    }

    class Chicken : Animal {
        public void LagEgg()
        {
            Console.WriteLine("{0}has lag en egg.", name);
        }

        public Chicken(string newName)
            : base(newName)
        { 
            
        }
    }

    class Animals :DictionaryBase
    { 
        public void Add(string newId, Animal newAnimal)
        {
            Dictionary.Add(newId, newAnimal);
        }

        public void Remove(string oldId,Animal oldAnimal)
        {
            Dictionary.Remove(oldId);
        }

        /// <summary>
        /// 索引符只能访问已添加的项,超过Count-1会产生超出索引异常
        /// </summary>
        /// <param name="animalIndex"></param>
        /// <returns></returns>
        public Animal this[string key]
        {
            get { return (Animal)Dictionary[key]; }
            set { Dictionary[key] = value; }
        }

        public new IEnumerator GetEnumerator()
        {
            foreach (DictionaryEntry d in Dictionary)
            {
                yield return (Animal)d.Value;
            }
        }

    class Program
    {

        static void Main(string[] args)
        {
            Animals animals = new Animals();
            animals.Add("111", new Cow("myCow1"));
            animals.Add("222", new Chicken("myChicken1"));

            foreach (Animal a in animals)
            {
                a.Feed();
            }
            Console.ReadLine();
        }
    }
View Code

属性块用做迭代器

class People:DictionaryBase
    {
        public void Add(string name, Person p)
        {
            this.Dictionary.Add(name, p);
        }

        public void Remove(string name)
        {
            this.Dictionary.Remove(name);
        }

        public Person this[string name]
        {
            get { return (Person)this.Dictionary[name]; }
            set { this.Dictionary[name] = value; }
        }

        public new IEnumerator GetEnumerator()
        {
            foreach (object d in Dictionary.Values)
            {
                yield return (Person)d;
            }

        }

        public IEnumerable Ages
        {
            get {
                foreach (object d in Dictionary.Values)
                {
                    yield return ((Person)d).Age;
                }
            }
        }
   
    }

    public class Person:IComparable
    {
        public string Name { get; set; }
        public int Age { get; set; }

        [System.Xml.Serialization.XmlElementAttribute("Books")]
        public Books Books { get; set; }


        public Person(string name, int age)
        {
            Name = name;
            Age = age;
        }

        public int CompareTo(object obj)
        {
            return this.Age-((Person)obj).Age;
        }
    }
原文地址:https://www.cnblogs.com/lidaying5/p/10539570.html