泛型将大量安全检查从执行时转移到了编译时进行,泛型实现了类型和方法的参数化。

为什么需要泛型
  • 将额外的信息作为方法或类型声明的一部分加以说明
  • IDE能基于额外的信息向程序员提供智能感知
  • 方法调用者对自己传递的值和方法返回值更有把握
  • 维护代码时,可以更好的掌握代码思路

日常使用的简单泛型

泛型字典
static Dictionary<string, int> CountWords(string text)
{
Dictionary<string, int> frequencies;
frequencies = new Dictionary<string, int>();//创建从单词到频率的新映射
string[] words = Regex.Split(text, @"\w+");//将文本分解为单词
foreach (string word in words)//添加或更新映射
{
if (frequencies.ContainsKey(word))
{
frequencies[word]++;
}
else
{
frequencies[word] = 1;
}
}
return frequencies;
 
}

#region 3—1,统计文本单词数
string text = @"Do you like greem eggs and Ham? I do not like them, Sam-i-AM";
Dictionary<string, int> frequencies = CountWords(text);
foreach (KeyValuePair<string, int> entry in frequencies)//打印映射中的每个键/值对
{
string word = entry.Key;
int frequency = entry.Value;
Console.WriteLine("{0}:{1}", word, frequency);
}
#endregion

泛型类型和类型参数

泛型两种形式:泛型类型(类,接口,委托,结构)和泛型方法
类型参数是真实类型的占位符。Dictionary<TKey, TValue>//TKey, TValue类型参数。 Dictionary<string, int>//string,int类型实参
没有为泛型类型参数提供类型实参,那么就是一个未绑定泛型类型
如果指定了类型实参,就是一个已构造类型。已构造类型可以是开发或封闭的,开放类型还包括一个类型参数,封闭类型每个部分都是明确的
可以认为封闭类型拥有开放类型的API。
泛型方法和判读泛型声明
static double TakeSquareRoot(int x)//平方根3-2返回
{
return Math.Sqrt(x);
}

#region 3-2List<T>.ConcertAll<TOutput>
List<int> integer = new List<int>();//创建并填充整个列表
integer.Add(1);
integer.Add(2);
integer.Add(3);
integer.Add(4);
Converter<int, double> converter = TakeSquareRoot;//创建委托
List<double> doubles;
doubles = integer.ConvertAll<double>(converter);//调用泛型方法来转换列表
foreach (double d in doubles)
{
Console.WriteLine(d);
}
#endregion

在非泛型方法中实现泛型方法

static List<T> MakeList<T>(T first, T second)
{
List<T> list = new List<T>();
list.Add(first);
list.Add(second);
return list;
}

List<string> list = MakeList<string>("Line 1", "Line 2");
List<string> list1 = MakeList("Line 1", "Line 2");//类型推断:只适用于泛型方法,不适用于泛型类型
Console.WriteLine(list.Capacity);
foreach (string i in list)
{
Console.WriteLine(i);
}

深化与提高

类型约束
类型参数可以被指定为任意类型时,它们未被约束
引用类型约束
确保使用的类型实参是引用类型。类型实参任何类,接口,委托,或已知是引用类型的另一个类型参数。
struct TefSample1<T> where T : class//引用类型约束,使用这种方式约束一个类型实参后,可以用==和!=来比较引用(包括NULL)
{
 
}

值类型约束

确保使用的类型实参是值类型,包括枚举,但是将可空类型排除在外
class TefSample<T> where T : struct//值类型约束,使用这种方式约束一个类型实参后,不可以用==和!=来比较
{
}

构造函数类型约束

必须是所有类型参数的最后一个约束,它检查是否有一个可用创建类型实例的无参构造函数。所有值类型都有一个默认的无参构造函数,而且显示声明的构造函数和无参构造函数是用相同的语法来调用的。
public static T CreateUbstance<T>() where T : new()//检查类型实例是否有一个可用于创建类型实例的构造函数
{
return new T();
}

T为int和object都是有效的,但T为string是无效的,因为string没有一个无参构造函数

转换类型约束
可以规定一个类型实参必须可以转换成另一个类型实参
class Sample<T> where T : Stream//转换类型约束
{
 
}

Sample<Stream> s = new Sample<Stream>();
组合约束

class Sqmple<T, U>
where T : class
where U : struct,T//组合约束,每一个值类型都有一个构造函数,假如已经有了一个值类型约束,就不允许在有构造函数约束
{
 
}

//指定多个接口,但只能指定一个类
class Sample2<T> where T : Stream, IEnumerable<string>, IComparable<int>
{
 
}

泛型方法类型实参的类型推断

类型推断只适用于泛型方法,不适用于泛型类型
实现泛型
默认值表达式
//3-4将一个值与类型默认值比较
static int CompaerToDefault<T>(T value) where T : IComparable<T>
{
return value.CompareTo(default(T));
}

#region 3-4以一个泛型方式将一个给定的值和一个默认值比较
Console.WriteLine(CompaerToDefault("x"));
Console.WriteLine(CompaerToDefault(10));
Console.WriteLine(CompaerToDefault(0));
Console.WriteLine(CompaerToDefault(-10));
Console.WriteLine(CompaerToDefault(DateTime.MinValue));
#endregion

直接比较

static bool AreReferencesEqual<T>(T first, T second) where T : class
{
return first == second;
}

#region 3-5 用==和!=进行引用比较
string name = "Jon";
string intro1 = "My name is" + name;
string intro2 = "My name is" + name;
Console.WriteLine(intro1 == intro2);
Console.WriteLine(AreReferencesEqual(intro1, intro2));
#endregion

对==进行重载,AreReferenxesEqual使用object

表示一对值
#region 表示一对值的泛型类
public sealed class Pair<T1, T2> : IEquatable<Pair<T1, T2>>
{
//每个封闭类型都有它自己的静态集
private static readonly IEqualityComparer<T1> FirstComparer = EqualityComparer<T1>.Default;
private static readonly IEqualityComparer<T2> SecondComparer = EqualityComparer<T2>.Default;
 
private readonly T1 first;
private readonly T2 second;
 
public Pair(T1 first, T2 second)
{
this.first = first;
this.second = second;
}
 
public T1 First { get { return first; } }
 
public T2 Second { get { return second; } }
 
public bool Equals(Pair<T1, T2> other)
{
return other != null && FirstComparer.Equals(this.First, other.First) && SecondComparer.Equals(this.Second, other.Second);
}
 
public override bool Equals(object obj)//重写
{
return base.Equals(obj as Pair<T1, T2>);
}
 
public override int GetHashCode()
{
return FirstComparer.GetHashCode(first) * 37 + SecondComparer.GetHashCode(second);
}
 
}
#endregion

#region 使用泛型方法的非泛型类型进行推断
public static class Pair
{
public static Pair<T1, T2> Of<T1, T2>(T1 first, T2 second)
{
return new Pair<T1, T2>(first, second);
}
}
#endregion

#region 表示一对值的泛型类
Pair<int, string> pair = new Pair<int, string>(10, "value");
#endregion
 
#region 使用泛型方法的非泛型类型进行推断
Pair<int, string> pair1 = Pair.Of(10, "VALUE");//类型推断根据方法进行,对于每一个方法实参,都尝试推断泛型方法的一些实参(简单推断技术),对于泛型方法要么推断要么全部显示指定。
 
#endregion

高级泛型

静态字段和静态构造函数
每个封闭的类型都有它自己的静态字段集
#region 3-8 证明不通的封闭类型具有不同的静态字段
//每个封闭类型有一个静态字段
TypeWithField<int>.field = "First";
TypeWithField<string>.field = "Secind";
TypeWithField<DateTime>.field = "Third";
 
TypeWithField<int>.PrinfField();
TypeWithField<string>.PrinfField();
TypeWithField<DateTime>.PrinfField();
#endregion

class TypeWithField<T>
{
public static string field;
public static void PrinfField()
{
Console.WriteLine(field + ":" + typeof(T).Name);
}
}

一个泛型类型可能嵌套在另一个泛型类型中,而且一个类型可能有多个泛型参数。

#region 3-9 嵌套泛型类型的静态构造函数
Outer<int> o = Outer.Of<int>();
 
Outer<int>.Inner<String, DateTime>.DummyMethod();
Outer<string>.Inner<int, int>.DummyMethod();
Outer<object>.Inner<string, object>.DummyMethod();
Outer<string>.Inner<string, object>.DummyMethod();
Outer<object>.Inner<object, string>.DummyMethod();
Outer<int>.Inner<string, DateTime>.DummyMethod();//任何封闭类型的构造函数只执行一次
 
#endregion

public class Outer<T>
{
public class Inner<U, V>
{
static Inner()
{
Console.WriteLine("Outer<{0}>.Inner<{1},{2}>",
typeof(T).Name,
typeof(U).Name,
typeof(V).Name);
}
public static void DummyMethod() { }
}
}

JIT编译器如果处理泛型

JIT为每个以值类型作为类型实参的封闭类型都创建不同的代码,所有使用引用类型作为类型实参的封闭类型都共享本地代码(所有引用都具有相同的大小。32位CLR上是4字节,64位CLR上是8字节)栈上一个引用所需空间始终相同。
ArrayList中,需要对每个字节进行装箱。
在32位CLR上:
ArrayList:8字节对象开销,4字节(1字节)数据本身,引用4字节
Liat<byte>:2字节(数据实际1字节)
泛型迭代
使用foreach,需要将集合的类型实参作为迭代变量类型使用
#region 3-10
class CountingEnumerable : IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()//隐式实现IEnumerable<T>
{
return new CountingEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()//显示实现IEnumerable
{
return GetEnumerator();
}
 
}
 
class CountingEnumerator : IEnumerator<int>
{
int current = -1;
 
public bool MoveNext() //接口IEnumerator的实现,将枚举数推进到集合的下一个元素。
{
current++;
return current < 10;
}
 
public int Current { get { return current; } }//隐式实现IEnumerator<T>.Current
 
object IEnumerator.Current { get { return Current; } }//显示实现IEnumerator.Current
 
public void Reset() //接口IEnumerator的实现,将枚举数设置为其初始位置,该位置位于集合中第一个元素之前。
{
current = -1;
}
 
public void Dispose() { }//接口IDisposable,执行与释放或重置非托管资源相关的应用程序定义的任务。
}
#endregion

#region 3-10 一个完整的泛型枚举
CountingEnumerable counter = new CountingEnumerable();
foreach (int x in counter)//foreach会自动负责Dispose调用事项,用于结束迭代时释放资源
{
Console.WriteLine(x);
}
#endregion

反射和泛型

1.对泛型使用typeof
typeof可以通过两种方式作用于泛型类型——获取泛型定义和获取特定的构造函数
#region 3-11对类型参数使用tupeof操作符
DemonstrateTypeof<int>();
#endregion

#region 3-11
static void DemonstrateTypeof<X>()
{
Console.WriteLine(typeof(X));//显示方法的类型参数
 
Console.WriteLine(typeof(List<>));//显示泛型类型
Console.WriteLine(typeof(Dictionary<,>));
 
Console.WriteLine(typeof(List<X>));//显示封闭类型(使用了类型参数)
Console.WriteLine(typeof(Dictionary<string, X>));
 
Console.WriteLine(typeof(List<long>));//显示封闭类型
Console.WriteLine(typeof(Dictionary<long, Guid>));
 
Console.WriteLine(typeof(Pair<,>));
Console.WriteLine(typeof(TypeWithField<>));
}
#endregion

在IL中,类型参数的数量是在框架所用的完整类型名称中指定的,在完整类型名称之后,会添加一个‘,然后是参数数量。

2.System。Type的属性和方法
任何特定的类型中有一个Type对象
#region 获取泛型和以构造Type对象的各种方式
string listTypeName = "System.Collections.Generic.List`1";//System.Collections.Generic.List`1
 
Type defByName = Type.GetType(listTypeName);
 
Type closedByName = Type.GetType(listTypeName + "[System.String]");//将类型实参放入方括号中
Type closeByMethod = defByName.MakeGenericType(typeof(string));
Type closedByTypeof = typeof(List<string>);
 
Console.WriteLine(closeByMethod == closedByName);
Console.WriteLine(closedByName == closedByTypeof);
 
Type defByTypeof = typeof(List<>);
Type defByMethod = closedByName.GetGenericTypeDefinition();
 
Console.WriteLine(defByMethod == defByName);
Console.WriteLine(defByName == defByTypeof);
#endregion

返回4次true

转载于:https://www.cnblogs.com/Tan-sir/p/5169200.html

用泛型实现参数化类型相关推荐

  1. java参数传入泛型类型_Java 泛型(参数化类型)

    Java 泛型 Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型. 泛型的本质是参数化类型,也就是说所 ...

  2. Typescript(真的)遵循泛型中参数化类型(T,U,V,W)的命名约定吗?

    我能想象的最接近于回答这个问题的方式(不仅仅是我的观点)是指向一些描述"TypeScript类型参数命名约定"的文档,并将其与您链接的Java泛型教程文档进行比较. 如果是这样,T ...

  3. 技术图文:C#语言中的泛型 I

    C#语言中的泛型 I 知识结构: 1. 泛型概述 泛型广泛应用于容器(Collections)和对容器操作的方法中. 从 .NET Framework2.0 开始,微软提供了一个新的命名空间Syste ...

  4. java泛型(二)、泛型的内部原理:类型擦除以及类型擦除带来的问题

    原 java泛型(二).泛型的内部原理:类型擦除以及类型擦除带来的问题 2012年08月29日 23:44:10 Kilnn 阅读数:56717 版权声明:本文为博主原创文章,未经博主允许不得转载. ...

  5. Effective Java读书笔记七:泛型(部分章节需要重读)

    第23条:请不要在新代码中使用原生态类型 从java1.5发行版本开始,Java就提供了一种安全的替代方法,称作无限制的通配符类型,如果要使用范型,但是确定或者不关心实际的参数类型,就可以用一个问号代 ...

  6. flutter 应用场景_【Flutter 1-12】Flutter手把手教程Dart语言——什么是泛型和泛型的使用场景...

    泛型 如果你查看数组的API文档,你会发现数组List的实际类型为List.<> 符号表示数组是一个泛型(或参数化类型)通常使用一个字母来代表类型参数,比如E.T.S.K 和 V 等等. ...

  7. Java千百问_05面向对象(012)_泛型是什么

    1.什么是泛型 泛型是Java SE 1.5的新特性,泛型即参数化类型,也就是说所操作的数据类型被指定为一个参数.  这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类.泛型接口.泛型方法.  ...

  8. java基础-泛型举例详解

    泛型 泛型是JDK5.0增加的新特性,泛型的本质是参数化类型,即所操作的数据类型被指定为一个参数.这种类型参数可以在类.接口.和方法的创建中,分别被称为泛型类.泛型接口.泛型方法. 一.认识泛型 在没 ...

  9. java范型_Java知识点总结(Java泛型)

    Java知识点总结(Java泛型) @(Java知识点总结)[Java, Java泛型] [toc] 泛型 泛型就是参数化类型 适用于多种数据类型执行相同的代码 泛型中的类型在使用时指定 泛型归根到底 ...

最新文章

  1. Linux shell 学习笔记(7)— 构建基本脚本(变量、重定向、管道、状态码)
  2. 独家 | 机器学习模型应用方法综述
  3. php nginx exec失败,小白问题:用nginx配置php后nginx无法启动。
  4. 【控制】能量函数Graph Laplacian Potential and Lyapunov Functions for Multi-Agent Systems
  5. C++类继承时的作用域嵌套,破解C++继承的一切秘密
  6. 你知道我们平时在CSS中写的%都是相对于谁吗?
  7. 【Verilog语法】读文件
  8. drbd实现mysql地热备_heartheartbeat+drbd+mysql主库热备
  9. 如何将Windows 10帐户还原为本地帐户(在Windows Store劫持它之后)
  10. 电大计算机网考选择题多少分,2016年度电大计算机网考选择题及标准答案.doc
  11. BugkuCTF-MISC题怀疑人生
  12. ae效果英文版翻译对照表_AE中英文对照
  13. 计算机电子表格相关简答题,2017年计算机一级excel操作试题及答案
  14. 无人机系统测试软件,无人机航测软件(pix4D)
  15. 通过Java 画一个太极图
  16. 数字疗法001 | 心理疾病太痛苦。把你的心理健康交给昭阳医生吧
  17. Android市场-开发者账号注册等-移动开放平台网址收藏
  18. joycon手柄拆解_任天堂Switch手柄腕带勿装反 取下需技巧
  19. win7下安装ubutun双系统
  20. 微软的软件工程现代化转型

热门文章

  1. AAAI Fellow 2019名单公布!罗杰波、刘欢等人入选
  2. 每日一道算法题 - LongestWord(easy-1)
  3. mysql备份和还原数据库
  4. scala面向对象之trait
  5. ACM模板--邻接表 无向图 Prim Kruskal Dijkstra
  6. Eigen: C++开源矩阵计算工具——Eigen的简单用法
  7. 六款小巧的HTTP Server
  8. Java虚拟机的研究与实现
  9. youtube根据channelId抓取栏目
  10. STM32F030控制LED