C#泛型、集合概念

为了满足灵活的数据结构,需要生成一种动态伸缩或只保存某个标准的对象。
集合类可划分为两大类:
非泛型集合(主要位于System.Collections命名空间) 通常设计为操作System.Object类型,因此是非常松散类型的容器。
泛型集合(主要位于System.Collections.Generic)
装箱可以正式定义为:显示的将值类型分配给System.Object变量的过程。
拆箱:把保存在对象引用中的值转换回栈上的相应值类型,从语法上来讲,拆箱操作更像是转换操作。
装箱拆箱的步骤:
1.必须在托管堆上分配一个新对象;
2.基于栈数据的值必须被转移到新分配的内存位置;
3.在拆箱时,保存在堆对象中的值必须转移会栈;
4.堆上无用的对象最后总会被回收。

static void Express()
{
    //在传递给要求object的成员时,值类型将自动装箱
    ArrayList myInts = new ArrayList();
    myInts.Add(10);
    myInts.Add(20);
    myInts.Add(30);
    //当将Object转换回栈数据时,会发生拆箱
    int i = (int)myInts[0];

    //由于WriteLine()要求Object类型,因此会再次发生自动装箱
    Console.writeline("Value of your int:{0}",i);
}

从这个例子中我们可以想象如果我们只是本地变量本地保存,我们再去确认变量的类型就变很难,
而且,装箱与拆箱伴随着代码性能的消耗,因而泛型的出现很好的解决了这一问题
泛型的优势:
1.泛型提供了更好的性功能,因为他们不会导致装箱火柴想的损耗;
2.泛型更类型安全,因为他们只包含我们制定的类型;
3.泛型大幅减少了构建自定义集合类型的需要,因为当创建泛型容器时指定了“类型的类型”。

static void UseGenericList()
{
    //该List<>只能容纳Person对象
    List<Person> morePersons = new List<Person>();
    morePersons.Add(new Person('safs','ming',24));
    writeline(morePersons[0]);

    //List<> Object
    List<Int> moreInts = new List<List>();
    moreInts.Add(10);
    moreInts.Add(20);
    int sum = moreInts[0]+moreInts[1];

    //it`s will error ,type isn`t right
    moreInts.Add(new Person('string<> ','string<>',int));
}

泛型参数的作用(只有类、结构、接口和委托可以使用泛型,枚举类型不可以)
IEnumerable ,符号读作of T。通俗称为占位符。类型参数(占位符)的名称可以随意取,它取决于创建该泛型项的人。
通常情况下,T表示类型,TKey或K表示键,TVaue或V表示值。
1.为泛型类/结构指定类型参数

public class List<T>:IList<T>,ICollection<T>,IEnumerable<T>,IReadOnlyList<T>,IList,ICollection,IEnumerable
{
    public void Add(T item);
    public ReadOnlyCollection<T> AsReadOnly();
    public int BinarySearch(T item);
    .....
}

当我们创建一个指定person对象的List时,就会执行将上面代码中所有的T参数转换为Person;

public class List<Person>:IList<Person>,ICollection<Person>,IEnumerable<Person>,IReadOnlyList<Person>,IList,ICollection,IEnumerable
{
    public void Add(Person item);
    public ReadOnlyCollection<Person> AsReadOnly();
    public int BinarySearch(Person item);
    .....
}

2.为泛型成员指定类型参数:

int[] myInts = {10,4,2,33,52}
//为Sort<>()泛型方法指定占位符
Array.Sort<int>(myInts);
foreach (int i in myInts)
{
    Console.WriteLine(i);
}

3.为泛型接口指定类型参数

public interface IComparable<Car>
{
    int CompareTO(T obj);
}

public  class Car :IComparable<Car>
{
    ...
    //实现IComparable<T>
    int IComparable<Car>.CompareTo(Car obj)
    {
        if(this.CarID > obj.CarID)
            return 1;
        if(this.CarID > obj.CarID)
            return -1;
        else
            return 0;       
    }
}

集合初始化

//初始化标准数组
int [] myArrayOfInts = {0,1,2,3,4,5,6,7,8,9};
//初始化整数的泛型List<>
List myGenericList = new List{0,1,2,3,4,5,6,7,8,9};

C#几乎扩展了所有接口的非泛型版本,是为了更好地实现类支持非泛型版本的旧功能。向上兼容性。
我们先来看一下,方便我们拿来直接使用的泛型方法有哪些:
List类:
List<>类是System.Collections.Generic命名空间的最常用的类型,是一个可以动态变化的列表;

static void UseGenericList()
{
    //构建一个Person对象列表 Person有三个属性:Firstname、Lastname、Age
    List<Person> people = new List<Person>()
    {
        new Person {Firstname="Homer",Lastname="Simple",Age=34},
        new Person {Firstname="Flame",Lastname="Haro",Age=23},
        new Person {Firstname="James",Lastname="Leons",Age=45}
    };
    Console.WriteLine("Items in List:{0}",people.Count);
    // 枚举列表
    foreach(Person p in people)
        Console.Writeline(p);
    //insert into a new obj.people
    people.insert(2,new Person{Firstname="Phines",Lastname="Leons",Age=23});
    Console.WriteLine("Items is list:{0}",people.Count);

    //将数据复制到新数组中
    Person[] arrayofPerson = people.toArray();
    for (int i;i<arrayofPerson.length;i++)
    {
        Console.WriteLine("First Names:{0}",arrayofPerson[i].Firstname);
    }

}

其中,toArray、Count等函数都是List定义的内部成员方法,更多详情请参考.NET FrameWork文档。
Stack类,表示以后进先出的方式维护数据的集合。包含Push和Pop方法,跟数据结构中的栈的数据存储理念类似;
以下代码创建一个Person对象的栈:

static void UseGenericStack()
{
    //构建一个Person对象列表 Person有三个属性:Firstname、Lastname、Age
    Stack<Person> Stackofpeople = new Stack<Person>();
    Stackofpeople.push(new Person {Firstname="Homer",Lastname="Simple",Age=34});
    Stackofpeople.push(new Person{Firstname="Flame",Lastname="Haro",Age=23});
    Stackofpeople.push(new Person {Firstname="James",Lastname="Leons",Age=45});
    //观察栈顶的项,取出,再次观察现在栈顶的元素重复操作
    Console.WriteLine("The First Person is {0}:",Stackofpeople.peek());
    Console.WriteLine("The First Person is {0}:",Stackofpeople.pop());
    ...
    //依次弹出栈顶元素
    //在最后检测栈是否是空
    try
    {
        Console.WriteLine("The First Person is {0}:",Stackofpeople.peek());
        Console.WriteLine("The First Person is {0}:",Stackofpeople.pop());
    }
    catch(InvalidOperationException ex)//InvalidOperationException是当栈为空时抛出的异常
    {
        Console.WriteLine(ex.Message);
    }
}

Queue<T>类,对应处理数据结构的队列。处理逻辑就像我们排队买票一样,先到先得。
Queue<T>类型的成员
Dequeue()     移除并返回Queue<T>开始处的对象
Enqueue()     在Queue<T>的末尾处添加一个对象
Peek()        返回Queue<T>开始处的对象,但不移除
用Person类构建一个Queu<T>,来模仿一群人开始买饭的现象;

// this is a Sup funcation
static void GetFood(Person p)
{
    Console.WriteLine("{0} person coming get your Food :",p.Firstname);
} 
//
static void UseGenericQueue()
{
    //构建一个Person对象列表 Person有三个属性:Firstname、Lastname、Age
    Queue<Person> peopleQ = new Queue<Person>();
    peopleQ.Enqueue(new Person {Firstname="Homer",Lastname="Simple",Age=34});
    peopleQ.Enqueue(new Person{Firstname="Flame",Lastname="Haro",Age=23});
    peopleQ.Enqueue(new Person {Firstname="James",Lastname="Leons",Age=45});
    //watch the firstperson in line
    Console.WriteLine("{0} is  first in line!:",peopleQ.Peek().Firstname);
    GetFood(peopleQ.Dequeue());
    GetFood(peopleQ.Dequeue());
    GetFood(peopleQ.Dequeue());
    try
    {
        GetFood(peopleQ.Dequeue());
    }
    catch(InvalidOperationException e)
    {
        Console.WriteLine("Error {0}",e.Message);
    }
}

创建自定义泛型方法
我们常会用到交换操作,如果我们需要操作一个证书的交换方法,我们可以这样写:
//交换两个整数
static void Swap(ref int a ,ref int b)
{
int temp;
temp= a ;
a= b;
b= temp;
}

如果就是这样还好,如果我们希望交换的是一系列不同类型的值,交换一条记录中的每一个字段值,有各种类型,那我们就要写多个类型的交换方法,这会给后期的维护带来很大的开销
我们也可以创建一个非泛型的方法来操作object对象,同样我们要面临拆箱、装箱、类型安全、显示转换等问题,当方法逻辑一样,知识参数不同,那么就可以使用泛型:

static void Swap<T>(ref T a ,ref T b)
{
    Console.WriteLine("this is Swap funcation,T type is :",typeof(T));
    T temp;
    temp = a;
    a = b;
    b = temp;
}

这样就可以随心所欲的进行各种不同类型的交换。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值