.net泛型理解
泛型简介:
泛型(Generic Type)是.NET Framework2.0最强大的功能之一。泛型的主要思想是将算法与数据结构完全分离开,使得一次定义的算法能作用于多种数据结构,从而实现高度可重用的开发。通过泛型可以定义类型安全的数据结构,而没有必要使用实际的数据类型,这将显著提高系统性能并得到高质量的代码(因为可以重用数据处理算法,没有必要复制类型特定的代码)。
泛型工作原理:
通过泛型可以定义类型安全并且对性能或工作效率无损害的类。表面上,C#泛型的语法和C++模板类似,但编译器在实现和支持他们的方式存在重要的差异。与C++模板相比,C#泛型可以提供增强的安全性,但在功能方面也受到某种程度的限制。在一些C++编译器中,在通过特定类型使用模板类之前,编译器甚至不会编译模板代码,当确实指定了类型时,编译器会以内联方式插入代码,并且将每个出现一般类型参数的地方替换为指定的类型。此外,每当使用特定类型时,编译器都会插入特定于该类型的代码,而不管是否已经在应用程序的其他位置为模板类指定了该类型,其中C++链接器负者解决该问题,但并不总是有效,而这也可能会导致代码膨胀,从而增加加载时间和内存足迹。
在.net Framewrok 2.0 中,泛型在IL和CLR本身中具有本机支持。在编译泛型c#代码时,像其他任何类型一样,首先编译器会将其编译为IL,但是,IL只包含实际特定类型的参数或占位符,并有专用的IL指令支持泛型操作。泛型代码的元数据中包含泛型信息。真正的泛型实例化工作是以“on-demand”的方式,发生在JIT编译时。当进行JIT编译时,JIT编译器用指定的类型实参来替换泛型IL代码元数据中的T,进行泛型类型的实例化。这会像JIT编译器提供类型特定的IL元数据定义,就好像从未涉及到泛型一样。JIT编译器可以确保参数正确性,实施类型安全检查,甚至执行类型特定的IntelliSense。
当.net将泛型IL代码编译为本机代码时,所产生的本机代码取决于指定的类型。JIT编译器跟踪已经生成特定类型的IL代码,如果本机指定的是值类型,则JIT编译器将泛型类型参数替换为指定的值类型,并且将其编译为本机代码。如果JIT编译器用已经编译为本机代码的值类型编译泛型IL代码,则只返回对IL代码的引用。因为JIT编译器在以后的所有场合中都将使用相同的值类型特定的IL代码,所以不会存在代码膨胀问题。如果本机指定的是引用类型,则JIT编译器将泛型IL嗲没种的泛型参数替换为object,并将其编译为本机代码。在以后的任何针对引用类型而不是泛型类型参数的请求中,JIT编译器只会重新使用实际代码,使用该代码,实例仍然按照它们离开托管堆的大小分配空间,并且不会存在强制类型转换。
泛型实现:
C#泛型支持包括类、结构、接口、委托四种泛型类型,以及其方法成员。此次,只以泛型类做简单演示:
class Program
{
static void Main(string[] args)
{
int obj = ;
Test<int> testInt = new Test<int>(obj);
Console.WriteLine(testInt.obj);// string obj1 = "hello";
Test<string> testString = new Test<string>(obj1);
Console.WriteLine(testString.obj);//hello Console.Read();
}
} class Test<T>
{
public T obj;
public Test(T obj)
{
this.obj = obj;
}
}
泛型约束:
在指定一个类型参数时,可以指定类型参数必须满足的约束条件。这里通过指定类型参数时使用where子句来实现的。泛型约束有:基类约束、接口约束、构造函数约束、引用类型和值类型约束。下面简单一一介绍:
基类约束:
使用基类约束,可以指定某个类型实参必须继承的基类。
基类约束有两个功能:
(1)它允许在泛型类中使用由约束指定的基类所定义的成员。例如,可以调用基类的方法或者使用基类的属性。如果没有基类约束,编译器就无法知道某个类型实参拥有哪些成员。通过提供基类约束,编译器将知道所有的类型实参都拥有由指定基类所定义的成员。
(2)确保类型实参支持指定的基类类型参数。这意味着对于任意给定的基类约束,类型实参必须要么是基类本身,要么是派生于该基类的类,如果试图使用没有继承指定基类的类型实参,就会导致编译错误。
基类约束使用下面形式的where子句:where T:base-class-name
T是类型参数的名称,base-class-name是基类的名称,这里只能指定一个基类。
class A
{
public void Func1()
{ }
} class B
{
public void Func2()
{ }
} class C<S, T>
where S : A
where T : B
{
public C(S s,T t)
{
//S的变量可以调用Func1方法
s.Func1();
//T的变量可以调用Func2方法
t.Func2();
}
}
接口约束:
接口约束用于指定某个类型参数必须应用的接口。接口的两个主要功能和基类约束完全一样。基本形式 where T:interface-name
interface-name是接口的名称,可以通过使用由逗号分割的列表来同时指定多个接口。如果某个约束同时包含基类和接口,则先指定基类列表,再指定接口列表。
interface IA<T>
{
T Func1();
} interface IB
{
void Func2();
} interface IC<T>
{
T Func3();
} class MyClass<T, V>
where T : IA<T>
where V : IB, IC<V>
{
public MyClass(T t,V v)
{
//T的对象可以调用Func1
t.Func1();
//V的对象可以调用Func2和Func3
v.Func2();
v.Func3();
}
}
构造器约束:
new()构造函数约束允许开发人员实例化一个泛型类型的对象。
一般情况下,我们无法创建一个泛型类型参数的实例。然而,new()约束改变了这种情况,它要求类型参数必须提供一个无参数的构造函数。在使用new()约束时,可以通过调用该无参构造函数来创建对象。基本形式: where T : new()
使用new()约束时应注意两点:
(1)它可以与其他约束一起使用,但是必须位于约束列表的末端。
(2)new()仅允许开发人员使用无参构造函数来构造一个对象,即使同时存在其他的构造函数。换句话说,不允许给类型参数的构造函数传递实参。
class A
{
public A()
{ }
} class B
{
public B()
{ }
public B(int i)
{ }
}
class C<T> where T : new()
{
T t;
public C()
{
t = new T();
}
} class D
{
public void Func()
{
C<A> c = new C<A>();
C<B> d = new C<B>();
}
}
值类型和引用类型约束:
如果引用类型和值类型之间的差别对于泛型代码非常重要,那么这些约束就非常有用。 基本形式: where T : class where T : struct 若同时存在其他约束的情况下,class或struct必须位于列表的开头。另外可以通过 使用约束来建立两个类型参数之间的关系 例如 class GenericClass2<T, V> where V:T{} -------- 要求V必须继承于T,这种称为裸类型约束(naked type constraint)。
public struct A { }
public class B { } public class C<T> where T : struct
{ } C<A> c1 = new C<A>();
C<B> c2 = new C<B>();//error
泛型的优点:
泛型使代码可以重用,类型和内部数据可以在不导致代码膨胀的情况下进行更改,而不管是值类型还是引用类型。可以一次性地开发、测试和部署代码,通过任何类型(包括将来的类型)来重用它,并且全部具有编译器支持和类型安全。因为泛型代码不会强行对值类型进行装箱和取消装箱,或者对引用类型进行向下强制类型转换,所以性能得到显著提高。对于值类型,性能通常会提高200%;对于引用类型,在访问该类型时,也可以达到预期性。
简单来说:使用泛型,可以极大地提高代码的重用度,同时还可以获得强类型的支持,避免了隐式的装箱、拆箱,在一定程度上提升了应用程序的性能。
再简单点:可重用、类型安全、高效率。
补充:
1、C#的泛型能力由CLR在运行时支持,它既不同于C++在编译时所支持的静态模板,也不同于Java在编译器层面使用“擦拭法”支持的简单的泛型。
2、C#的泛型支持包括类、结构、接口、委托四种泛型类型,以及方法成员。
3、C#的泛型采用“基类,接口,构造器,值类型/引用类型”的约束方式来实现对类型参数的“显式约束”,它不支持C++模板那样的基于签名的隐式约束。
网上找到一个介绍泛型的好文章:
引用:
.net泛型理解的更多相关文章
- 转载.net泛型理解说明
net泛型理解 泛型简介: 泛型(Generic Type)是.NET Framework2.0最强大的功能之一.泛型的主要思想是将算法与数据结构完全分离开,使得一次定义的算法能作用于多种数据结构,从 ...
- C#泛型理解(转)
[译]C# 理解泛型 PDF 浏览:http://www.tracefact.net/document/generics-in-csharp.pdf源码下载:http://www.tracefact ...
- Map接口下的集合和泛型理解
一.Map接口 1. Map接口就是最顶层了,上面没有继承了.Map是一个容器接口,它与前面学的List.Set容器不同的是前面学的这些容器,一次只能传入一个元素,但是Map容器一次可以传入一对元素( ...
- 泛型理解及应用(二):使用泛型编写通用型Dao层
相信目前所有的IT公司网站在设计WEB项目的时候都含有持久层,同样地使用过Hibernate的程序员都应该看过或者了解过Hibernate根据数据库反向生成持久层代码的模板.对于Hibernate生成 ...
- java泛型理解。代码更明了。
泛型数据java基础,但真正理解需要悉心品尝.毕竟在工作中用到的是在是太多了. 不要以为new ArrayList<>这就是泛型,这只能属于会使用. 在工作中,相对于现有的项目源码的数据库 ...
- Java泛型理解
Java泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型.当需要使用某一种算法时,又无法具体算法的数据类型,或者想指定类型值的上限或下限,那么这时就需要Java泛型来大显身手 ...
- C#泛型理解(一)
一.什么是泛型 泛型是C#语言和公共语言运行库(CLR)中的一个新功能,它将类型参数的概念引入.NET Framework.类型参数使得设计某些类和方法成为可能,例如,通过使用泛型类型参数T,可以大大 ...
- 窥探Swift之使用Web浏览器编译Swift代码以及Swift中的泛型
有的小伙伴会问:博主,没有Mac怎么学Swift语言呢,我想学Swift,但前提得买个Mac.非也,非也.如果你想了解或者初步学习Swift语言的话,你可以登录这个网站:http://swiftstu ...
- Java学习笔记(二一)——Java 泛型
[前面的话] 最近脸好干,掉皮,需要买点化妆品了. Java泛型好好学习一下. [定义] 一.泛型的定义主要有以下两种: 在程序编码中一些包含类型参数的类型,也就是说泛型的参数只可以代表类,不能代表个 ...
随机推荐
- Html - 圆圈border
很多场景下需要对元素加入圆圈.但光靠border-radius其实还要调很久,所以做一下笔记 #binggan .mui-icon { display: inline-block; margin: 3 ...
- php常用的对字符串进行加密的算法
1. 返回文件扩展名 function getformat($file) { $ext=strrchr($file,"."); $format=strtolower($ext); ...
- 动态input file多文件上传到后台没反应的解决方法!!!
其实我也不太清除具体是什么原因,但是后面就可以了!!! 我用的是springMVC 自带的文件上传 1.首先肯定是要有springMVC上传文件的相关配置! 2.前端 这是动态input file上传 ...
- Web 在线文件管理器学习笔记与总结(11)获取文件夹信息 (12)返回上一级操作
(11)获取文件夹信息 文件夹没有修改操作. index.php: <?php require 'dir.func.php'; require 'file.func.php'; require ...
- centos7 设置中文
查看系统版本[root@webtest76 ~]# cat /etc/redhat-releaseCentOS Linux release 7.0.1406 (Core) [root@localhos ...
- IS_POST:判断是否存在POST提交
IS_POST:判断是否存在POST提交 在程序中可以使用IS_POST来做优化..如果有提交.我们再执行下一步动作.节省开销
- linux下创建和删除软、硬链接
linux下创建和删除软.硬链接 在Linux系统中,内核为每一个新创建的文件分配一个Inode(索引结点),每个文件都有一个惟一的inode号.文件属性保存在索引结点里,在访问文件时,索引结点被复制 ...
- buffer overflow
Computer Systems A Programmer's Perspective Second Edition We have seen that C does not perform any ...
- Python For Data Analysis -- IPython
IPython Basics 首先比一般的python shell更方便一些 比如某些数据结构的pretty-printed,比如字典 更方便的,整段代码的copy,执行 并且可以兼容部分system ...
- git 第一次初始化
Command line instructions Git global setup git config --global user.name "{名字}({工号})" git ...