黑马程序员--泛型的一些理解

时间:2023-02-19 14:01:00

---------------------- Windows Phone 7手机开发.Net培训、期待与您交流! ---------------------- ----------------------

泛型:在定义的时候不指定具体的类型结构,可以推迟到后面的声明或实例化时指定。


原因:避免在运行时强制转换或装箱拆箱操作的成本、风险。


名称空间:System.Collection.Generic


先了解下装箱和拆箱的概念:

装箱:把值类型转换为Object类型。

拆箱:取消装箱,从对象中提取值类型。

            int i = 123;
object o = i; //装箱:值类型到object类型

int j = (int)o; //拆箱:object到值类型

装箱是隐式的,拆箱是显式的。装箱与拆箱过程需要大量的计算

黑马程序员--泛型的一些理解


对值类型装箱会在堆中分配一个对象实例。


堆(Heap):从高地址开始分配,程序员分配,比如C#中实例化 new

栈(Stack):从低地址开始分派,编译器自动分配,存放函数的参数值,局部变量等。



泛型适用范围:

泛型可以创建自己的泛型类、泛型方法、泛型委托、泛型借口、泛型事件等。最常见的用途是创建集合、类。


泛型的特点:

1.若实例化的参数类型相同,编译器会重复使用该类型,防止代码膨胀。

2.拥有丰富的元数据,可以应用于强大的反射技术。


泛型约束: where关键字

在定义泛型类时,可以在实例化类时对类型参数的类型种类施加限制。 如果客户端代码尝试使用某个约束所不允许的类型来实例化类,则会产生编译时错误。 这些限制称为约束。 约束是使用 where 上下文关键字指定的。 下表列出了六种类型的约束:

约束

说明

T:结构

类型参数必须是值类型。 可以指定除 Nullable 以外的任何值类型。

T:类

类型参数必须是引用类型;这一点也适用于任何类、接口、委托或数组类型。

T:new()

类型参数必须具有无参数的公共构造函数。 当与其他约束一起使用时,new() 约束必须最后指定。

T:<基类名>

类型参数必须是指定的基类或派生自指定的基类。

T:<接口名称>

类型参数必须是指定的接口或实现指定的接口。 可以指定多个接口约束。 约束接口也可以是泛型的。

T:U

为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。


例子: 

        public class BaseClass { } //声明父类
public class PersonClass : BaseClass { } //子类,继承父类BaseClass
public class OtherClass<T> where T : BaseClass { }//泛型类。类型参数T只能继承于BaseClass

OtherClass<PersonClass> other=new OtherClass<PersonClass>(); //这个声明能正常使用
表示T只能继承于BaseClasee,其实改成T where int  更好理解,

在里面定义的变量类型T只能来自 int类型。


泛型关键字:default及运算符 ==!=

在预先未知以下情况时,如何将默认值分配给参数化类型T:

1.T是引用类型还是值类型。

2.若T为值类型,则它是数值还是结构。

因此在不确定的情况下,避免使用运算符== 、 !=

示例:

        public class OtherClass<T> where T : BaseClass {
T test=default (T);

public void Msg()
{
if (test == null)
{
MessageBox.Show("test的值为null");
}
else
{
MessageBox.Show("test的值不为null");
}
}
}



泛型集合:List<T> 、Dictionary<K,V>

List<T>  对应的是非泛型集合ArrayList。

它本身就是个类,所以在声明使用时,T要变成具体的数据结构。

            //非泛型,加入不同的值,会造成装箱拆箱的开销
ArrayList alst = new ArrayList();
alst.Add(123);
alst.Add("字符串");
//泛型List<T>
List<int> lst = new List<int>();
lst.Add(1);
//lst.Add("2"); //报错,一方面限制了类型,一方面避免了装箱拆箱的开销

Dictionary<K,V>:表示键/值对集合。其中键的值K必须是唯一的。

Dictionary<K,V>.KeyColletion:表示Dictionary<K,V>的键集合。

Dictionary<K,V>.ValueColletion:表示Dictionary<K,V>的值集合。


泛型类:

过程:从一个现有的具体类开始,逐一将每个类型更改为类型参数,直至达到通用化和可用性的最佳平衡。

泛型类可以从具体的,封闭式构造或开放式构造基类继承:


        public class BaseClass { };
public class BaseClassGeneric<T> { };
public class PersonClass<T> : BaseClass { } //具体的
public class PersonClosed<T> : BaseClassGeneric<int> { }; //封闭构造
public class PersonOpen<T> : BaseClassGeneric<T> { };//开放构造



泛型方法:

在泛型类中定义

        class GenericList<T>
{
public void ShowMsg<Y>(T s)
{
T i = s;
MessageBox.Show("你好"+s);
}

}
private void btnFxMethod_Click(object sender, EventArgs e)
{
GenericList<string> ls = new GenericList<string>();
ls.ShowMsg("游客");
}
}


泛型委托:

可以定义自己的类型参数。引用泛型委托的代码可以指定类型参数以创建已关闭的构造类型,就像实例化泛型类或调用泛型方式一样。

示例:

        public delegate void Del<T>(T item); //定义个泛型委托
public static void Notify(int i); //定义个方法
Del<int> m1 = new Del<int>(Notify); //声明委托变量m1
Del<int> m2 = Notify; //也可以这么声明


基础类库中的泛型:

System.Collections.Generic,其中包含了一些已经可以使用的泛型容器类和相关的接口。和早期版本的.NET框架提供的非泛型容器类相比,这些类和接口更高效且是类型安全的。在设计、实现自定义的容器类之前,请你考虑是否使用或继承所列出类中的一个。


泛型类或接口 描述 对应的非泛型类型
Collection<T>ICollection<T> 为泛型容器提供基类 CollectionBaseICollection
Comparer<T>IComparer<T>IComparable<T> 比较两个相同泛型类型的对象是否相等、可排序。 ComparerIComparerIComparable
Dictionary<K, V>IDictionary<K,V> 表示用键组织的键/值对集合。 HashtableIDictionary
Dictionary<K, V>.KeyCollection 表示Dictionary<K, V>中键的集合。 None.
Dictionary<K, V>.ValueCollection 表示Dictionary<K, V>中值的集合。 None.
IEnumerable<T>IEnumerator<T> 表示可以使用foreach 迭代的集合。 IEnumerableIEnumerator
KeyedCollection<T, U> 表示有键值的集合。 KeyedCollection
LinkedList<T> 表示双向链表。 None.
LinkedListNode<T> 表示LinkedList<T>中的节点。 None.
List<T>IList<T> 使用大小可按需动态增加的数组实现 IList 接口 ArrayListIList
Queue<T> 表示对象的先进先出集合。 Queue
ReadOnlyCollection<T> 为泛型只读容器提供基类。 ReadOnlyCollectionBase
SortedDictionary<K, V>  表示键/值对的集合,这些键和值按键排序并可按照键访问,实现IComparer<T>接口。 SortedList
Stack<T> 表示对象的简单的后进先出集合。 Stack


---------------------- Windows Phone 7手机开发.Net培训、期待与您交流! ---------------------- ----------------------