.NET泛型解析(下)
上一篇对.NET中的泛型进行了详细的介绍以及使用泛型的好处是什么,这篇将更加深入的去了解泛型的其他的知识点,重头戏.
【1】泛型方法
public class GenericType<T>
{ private T G_Value; public T Convert<T> { T res = (T)Convert.ChangeType(G_value,typeof(T)); return res; } }
static void Test<T >(ref T t1,ref T t2)
{
T temp = t1;
t1 = t2;
t2 = temp;
}
这是我们定义的一个泛型方法,第一个参数类型为 T,第二个也为 T,说明这两个类型是一致的。那么我们在调用的时候应该这样 :
int i = , j = ; Test( ref i, ref j);
而如果我们两个实参的类型不统一的话,那么就会引发编译异常例如 :

开放类型和封闭类型
class DictionaryStringKey <T> : IEnumerable<T>
{
public IEnumerator<T> GetEnumerator()
{
throw new NotImplementedException();
} System .Collections. IEnumerator System. Collections.IEnumerable .GetEnumerator()
{
throw new NotImplementedException();
}
}
在上述代码中,有一个DictionaryStringKey的类,继承了一个IEnumable<T>的泛型,那么根据我们的开放类型它在调用的时候是不只是具体的实参,并且不能被构造实例的.
static void Main( string[] args)
{
object o = null;
Type t = typeof( DictionaryStringKey <>);
o = CreateInstance(t);
Console .ReadLine(); } private static object CreateInstance( Type t)
{
object o = null;
try
{
o = Activator . CreateInstance(t);
Console .WriteLine( @" 创建了 " + t + "的实例 " , t .ToString());
}
catch (Exception ex)
{
o = Activator . CreateInstance(t);
Console .WriteLine( @" 创建 " + t + "的实例失败 " , t .ToString());
} return o;
}
上述代码中我尝试着对开放类型进行实例化,结果报出异常 :

当我们传入实参之后,那么它就是一个封闭类型,这样我们就可以进行构造实例了.
static void Main( string[] args)
{
object o = null;
Type t = typeof( DictionaryStringKey <string > );
o = CreateInstance(t);
Console .ReadLine(); }
【2】泛型接口
泛型的主要作用就是定义泛型的引用类型和值类型,在CLR中,对于泛型接口的支持也是很重要的,因为这样更有益与程序的扩展性, 另外一点如果没有泛型接口我们每次使用非泛型接口时都会进行装箱操作(例如: IComparable),并且会失去编译时的安全性(因为它是非泛型的,较之泛型的好处之一).
那么CLR提供了对于泛型接口的支持,对于引用类型和值类型可以通过制定实参的方式来实现泛型接口,同时也可以保持未指定状态来实现一个泛型接口( 接受者也可以是泛型 , 可以在后期进行指定类型)
实例 1 : 声明一个泛型接口
interface IPair <T>
{
T First { get; set ; }
T Second { get; set ; }
}
class Pair <T> : IPiar< T>
{
public T First
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
} public T Second
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
}
CLR泛型接口的支持对于集合类型来讲尤其重要,同时泛型在集合类型中较为常用,如果没有泛型那么我们所使用List的时候都要依赖与System.Collections,我们在每次访问的时候都需要执行一次转换,如果使用泛型接口,就可以避免执行转型,因为参数化的接口能实现更强的编译时绑定.
实例 3 : 在一个类中多次实现相同的接口
interface IContainer <T>
{
ICollection<T > Items { get ; set; }
} public class Person : IContainer<A >,IContainer <B>
{ public ICollection <A> Items
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
} ICollection<B > IContainer <B>. Items
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
}
Items属性使用一个显式接口实现多次出现,每一次,类型参数都有所不同,如果没有泛型,这是做不到的,在非泛型的情况下,CLR只允许一个显式的IContainer.Items属性.
【4】泛型约束(主要约束,次要约束,构造器约束)
约束也可以理解为是一种规则,意思就是我们所编写的所有泛型,你在调用的时候,应该给我传输那些类型的实参。
struct Generic<T>(T t1) where : class
class ConstraintOfStruct <T> where T : struct
{
public T result()
{
return new T();
}
}
在代码中,我们最后返回的是new T(),这个是没有问题的,因为我们已经可以肯定T就是值类型,所有的值类型都有一个隐式的构造函数,那么如果我们将 约束条件改为 class的话,那么就会出异常,因为不是所有的引用类型都可以实例化.
实例 6 : 反面教材 - 约束为引用类型时进行实例化.

public T CreateInatance<T >() where T : new()
{
return new T();
}
在方法createInstance中,要求我们必须传入一个无参的构造函数,例如:我们可以传入 object,struct,stream等,但是不能传入 string,Directory等.
接口约束:
class ConstraintOfStruct <T> where T : class,IEquatable <T> ,IComparable<T>
{
}
class Sample<T> where T : class ,IDisposable,new(){}
class Sample<T> where T : struct,IDisposable{}
class Sample<T,U> where T : Stream where U : IDisposable{}
class Sample<T> where T : class ,struct
【5】泛型类型转型
public static T Desercialies <T > (Stream stream, IFormatter formatter)
{
return (T)formatter. Deserialize(stream);
}
formatter 负责将流转换为 Object,返回一个Object类型,我们在使用泛型调用的时候应该这样来 :
string result = Desercialies <string > (stream, formatter);
上述的代码看着是一种强制转换,但是仍然执行了隐式的转换,就和使用非泛型 string result = (string)Desercialies(stream, formatter); 一样
【6】泛型和属性
属性也可以应用到泛型类型中,使用的方式和非泛型类型相同.自定义的属性只允许引用开发泛型类型
class MyClass<T,S> where T :class
where S : struct
{
public T MyName { get; set; }
public S MyCode { get; set; }
public List<T> MyCourse { get; set; }
public List<S> MyStudyHistory { get; set; }
}
上述我们定义了一个MyClass 类,这个类有两个参数一个是引用类型一个是值类型.在属性MyName,MyCourse的类型都是引用类型,MyCode的类型都为值类型
泛型类型构造器:
class Pair < T> : IPiar< T >
{
private T _first; public T First
{
get { return _first; }
set { _first = value; }
}
private T _second; public T Second
{
get { return _second; }
set { _second = value; }
}
public Pair(T first,T second)
{ }
}
interface IPiar < T> { }
泛型的构造器不需要添加类型参数来与类的声明一致.
先到这里, 下一篇着重分享协变和逆变,否则这一篇符太长,不利于以后的查看.
泛型委托和泛型反射留在深入总结委托和反射的时候进行总结。
同时,希望给在阅读的你带来一些帮助。
.NET泛型解析(下)的更多相关文章
- WCF 已知类型和泛型解析程序 KnownType
数据协定继承 已知类型和泛型解析程序 Juval Lowy 下载代码示例 自首次发布以来,Windows Communication Foundation (WCF) 开发人员便必须处理数据协定继承方 ...
- Java泛型解析(01):认识泛型
Java泛型解析(01):认识泛型 What Java从1.0版本号到如今的8.中间Java5中发生了一个非常重要的变化,那就是泛型机制的引入.Java5引入了泛型,主要还是为了满足在199 ...
- Java泛型解析(02):通配符限定
Java泛型解析(02):通配符限定 考虑一个这种场景.计算数组中的最大元素. [code01] public class ArrayUtil { public static <T&g ...
- Java泛型解析(03):虚拟机运行泛型代码
Java泛型解析(03):虚拟机运行泛型代码 Java虚拟机是不存在泛型类型对象的,全部的对象都属于普通类,甚至在泛型实现的早起版本号中,可以将使用泛型的程序编译为在1.0虚拟机上可以执行的 ...
- C#函数式程序设计之泛型(下)
C#函数式程序设计之泛型(下) 每当使用泛型类型时,可以通过where字句对泛型添加约束: + 这个例子直观地声明了一个约束:类型T必须与ListItem<string>相匹配.泛型类 ...
- 使用GSON和泛型解析约定格式的JSON串(转)
时间紧张,先记一笔,后续优化与完善. 解决的问题: 使用GSON和泛型解析约定格式的JSON串. 背景介绍: 1.使用GSON来进行JSON串与java代码的互相转换. 2.JSON的格式如下三种: ...
- Java泛型解析(04):约束和局限性
Java泛型解析(04):约束和局限性 前两节.认识和学习了泛型的限定以及通配符.刚開始学习的人可能须要一些时间去体会到泛型程序设计的优点和力量,特别是想成为库程序猿的同学就须要下 ...
- android多线程-AsyncTask之工作原理深入解析(下)
关联文章: Android 多线程之HandlerThread 完全详解 Android 多线程之IntentService 完全详解 android多线程-AsyncTask之工作原理深入解析(上) ...
- Android View系统解析(下)
转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/38426471(来自singwhatiwanna的csdn博客) Androi ...
随机推荐
- linux第六周
一.知识概要 进程的描述 进程描述符task_struct数据结构(一)进程描述符task_struct数据结构(二)进程的创建 进程的创建概览及fork一个进程的用户态代码理解进程创建过程复杂代码的 ...
- BZOj 墨墨的等式(转化为最短路)题解
题意:中文题意不解释... 思路:这道题居然可以转化为最短路orz,要等式有非负整数解,我们可以转化一下:每个ai不限数量,问你能用ai数组拼出多少个Bmin~Bmax范围内的数,有点像完全背包的感觉 ...
- Gym 101246J Buoys(三分查找)
http://codeforces.com/gym/101246/problem/J 题意: 给定x轴上的n个点的坐标,按顺序从左到右给出,现在要使得每个点的间距相同,可以移动每个点的坐标,但是不能改 ...
- 使用javascript模拟常见数据结构(二)
四.链表 每种语言都实现了数组.这种数据结构非常方便,提供了一个便利的[]语法来访问它的元素.然而,这种数据结构有一个缺点:(在大多数语言中)数组的大小是固定的,从数组的起点或中间插入或移除项的成本很 ...
- Windows服务程序_测试01
1. #include <stdio.h> #include <Windows.h> #include <tchar.h> #include <process ...
- PHP-----------HTTP请求的第三方接口
开发中常常遇到接口请求这个功能,后台也不例外,因为遇到了,所以写一篇. 前段时间做商城后台时,需要用到第三方物流接口查询物流信息. post: /**** * @param $url * @param ...
- hdu1846巴什博弈
巴什博弈:只有一堆n个物品,两个人轮流从这堆物品中取物, 规定每次至少取一个,最多取m个.最后取光者得胜. 结论:只要不能整除,那么必然是先手取胜,否则后手取胜. #include<map> ...
- Lua 中的 function、closure、upvalue
Lua 中的 function.closure.upvalue function,local,upvalue,closure 参考: Lua基础 语句 lua学习笔记之Lua的function.clo ...
- 记录vue中一些有意思的坑
记录vue中一些有意思的坑 'message' handler took 401ms 在出现这个之前,我一直纠结于 是如何使用vue-router或者不使用它,通过类似的v-if来实现.结果却出现这个 ...
- java并发编程:线程安全管理类--原子包--java.util.concurrent.atomic
java.util.concurrent.atomic 的描述 AtomicBoolean 可以用原子方式更新的 boolean 值. AtomicInteger 可以用原子方式更新的 int 值. ...