泛型可以创建独立于被包含类型的类和方法。

C++模板与泛型相似。

泛型优点性能

System.Collections 和 System.Collections.Generic

名称空间泛型和非泛型集合类。

值类型存储在栈上,引用类型存储在堆上。C#类是引用类型,结构是值类型。

从值类型转化为引用类型称为装箱。方法需要把一个对象作为参数,传递了一个值类型,装箱操作就会自动进行。

装箱的值类型可以使用拆箱操作转换为值类型。在拆箱时,需要使用类型强制转换运算符。

ArrayList list = new ArrayList();
list.Add(); int i1 = (int) list[]; foreach (int i2 in list)
{
Console.WriteLine(i2);
}

装箱和拆箱操作很容易使用,但性能损失比较大,遍历尤其如此。

List<T> 泛型类,不再进行装箱和拆箱操作

List<int> list = new List<int>();
list.Add(); int i1 = list[]; foreach (int i2 in list)
{
Console.WriteLine(i2);
}

类型安全

ArrayList

ArrayList list = new ArrayList();
list.Add();
list.Add("mystring");
list.Add(new ArrayList()); foreach (int i2 in list)
{
Console.WriteLine(i2);
}

并不是所有元素都可以强制转换int。所以运行抛出异常。

错误应尽早发现。List<T> 泛型类就不会。

 List<int> list = new List<int>();
list.Add();
list.Add("mystring");
list.Add(new ArrayList());

直接在编译前,就报错。

二进制代码重用

List<Byte> list = new List<Byte>();
list.Add(); List<string> list2 = new List<string>();
list2.Add("hello");

代码的扩展

引用类型在实例化的泛型类中只需要4个字节的内存地址(32位系统),就可以引用一个引用类型。值类型包含在实例化的泛型类的内存中,因为每个值类型对内存的要求不同,所以值类型实例化新类。

命名约定

  • 泛型类行的名称用字母T作为前缀。
  • 如果没有特殊要求,泛型类型允许用任意类替代,且只使用一个泛型类型,就可以用字符T作为泛型类型名称。
 public class LinkedList<T>
{ }
  • 如果泛型类型有特定要求(如实现一个接口或派生自基类),或者使用了两个或多个泛型类型。就应给泛型类型使用描述性的名称:
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);

创建泛型类

一个非泛型的列表类。

public class LinkedListNode
{
public LinkedListNode(object value)
{
this.Value = value;
} public object Value { get; private set; } public LinkedListNode Next { get; internal set; }
public LinkedListNode Prev { get; internal set; }
} public class LinkedList : IEnumerable
{
public LinkedListNode First { get; private set; }
public LinkedListNode Last { get; private set; } public LinkedListNode AddLast(object node)
{
LinkedListNode newNode = new LinkedListNode(node); if (First == null)
{
First = newNode;
Last = First;
}
else
{
LinkedListNode previous = Last;
Last.Next = newNode;
Last = newNode;
Last.Prev = previous;
}
return newNode;
} public IEnumerator GetEnumerator()
{
LinkedListNode current = First;
while (current != null)
{
yield return current.Value;
current = current.Next;
}
}
}

yield语句创建一个枚举器的状态机。

 LinkedList _linked = new LinkedList();
_linked.AddLast();
_linked.AddLast();
_linked.AddLast(""); foreach (int i2 in _linked)
{
Console.WriteLine(i2);
}

改成泛型类

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace ConsoleApplicationCShape
{
public class LinkedListNode<T>
{
public LinkedListNode(T value)
{
this.Value = value;
} public T Value { get; private set; }
public LinkedListNode<T> Next { get; internal set; }
public LinkedListNode<T> Prev { get; internal set; }
} public class LinkedList<T> : IEnumerable<T>
{
public LinkedListNode<T> First { get; private set; }
public LinkedListNode<T> Last { get; private set; } public LinkedListNode<T> AddLast(T node)
{
var newNode = new LinkedListNode<T>(node);
if (First == null)
{
First = newNode;
Last = First;
}
else
{
Last.Next = newNode;
Last = newNode;
}
return newNode;
} public IEnumerator<T> GetEnumerator()
{
LinkedListNode<T> current = First; while (current != null)
{
yield return current.Value;
current = current.Next;
}
} IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
class Program
{
static void Main(string[] args)
{
LinkedList<int> _linked = new LinkedList<int>();
_linked.AddLast();
_linked.AddLast();
_linked.AddLast(); foreach (int i2 in _linked)
{
Console.WriteLine(i2);
} Console.ReadLine();
}
}
}

泛型类的功能

泛型文档类管理

class DocumentManage<T>
{
private readonly Queue<T> documentQueue = new Queue<T>(); public void AddDocument(T doc)
{
lock (this)
{
documentQueue.Enqueue(doc);
}
} public bool IsDocumentAvilable
{
get { return documentQueue.Count > ; }
}
}

默认值

null不能赋值给泛型类型。原因是 泛型类型也可以实例化为值类型,而null只能用于引用类型。

通过 default 将 null 赋值引用类型。

public T GetDocument()
{
T doc = default(T);
lock (this)
{
doc = documentQueue.Dequeue();
}
return doc;
}

default关键字根据上下文有多种含义。 在switch表示默认值。在泛型中,用于泛型初始化 引用类型 赋值 null,值类型赋值0。

约束

public interface IDocument
{
string Title { get; set; }
string Content { get; set; }
} public class Document : IDocument
{
public Document()
{ } public Document(string title, string content)
{
this.Title = title;
this.Content = content;
} public string Title { get; set; }
public string Content { get; set; }
} class DocumentManage<TDocument> where TDocument: IDocument
{
private readonly Queue<TDocument> documentQueue = new Queue<TDocument>(); public void AddDocument(TDocument doc)
{
lock (this)
{
documentQueue.Enqueue(doc);
}
} public bool IsDocumentAvilable
{
get { return documentQueue.Count > ; }
} public TDocument GetDocument()
{
TDocument doc = default(TDocument);
lock (this)
{
doc = documentQueue.Dequeue();
}
return doc;
} public void DisplayAllDocuments()
{
foreach (TDocument doc in documentQueue)
{
Console.WriteLine(doc.Title);
}
}
} class Program
{
static void Main(string[] args)
{
DocumentManage<Document> dm = new DocumentManage<Document>();
dm.AddDocument(new Document("Ttile A", "Content A"));
dm.AddDocument(new Document("Ttile B", "Content B")); dm.DisplayAllDocuments(); while (dm.IsDocumentAvilable)
{
Document d = dm.GetDocument();
Console.WriteLine(d.Content);
}
}
}

约束 TDocument 必须 实现 IDocment

 where TDocument: IDocument

泛型其他的几种约束类型

value = where T:struct      对结构约束,类型T必须是值类型
where T:class 约束,类型T必须是引用类型
where T:IFoo 约束,类型T必须实现IFoo
where T:Foo 约束,类型T必须派生自基类IFoo
where T:new() 约束,类型T必须具有无参的构造函数
where T1:T2 约束,类型T1派生自泛型类型T2,称为裸类型约束

继承

实现泛型接口

public class LinkedList<T> : IEnumerable<T>

泛型派生泛型基类

public class Base<T>
{ } public class Derived<T> : Base<T>
{ }

指定基类类型

public class Derived<T> : Base<string>
{ }
public abstract class Calc<T>
{
public abstract T Add(T x, T y);
public abstract T Sub(T x, T y);
} public class IntCalc : Calc<int>
{
public override int Add(int x, int y)
{
return x + y;
} public override int Sub(int x, int y)
{
return x - y;
}
}

静态成员

泛型类的静态成员,只能在类的静态成员类访问。

public class StaticDemo<T>
{
public static int x;
} StaticDemo<string>.x = ;
StaticDemo<int>.x = ;
Console.WriteLine(StaticDemo<string>.x + " " + StaticDemo<int>.x);

泛型接口

使用泛型可以定义接口,在接口中定义的方法可以带泛型参数。

public interface IComparable<in T>
{
int CompareTo(T other);
} public class Person : IComparable<Person>
{
private string LastName; public int CompareTo(Person other)
{
return this.LastName.CompareTo(other.LastName);
}
}

协变和抗变

泛型接口是不变的。通过协变和抗变为泛型接口和泛型委托添加了一个重要的扩展。协变和抗变指对参数和返回值的类型进行转换。

Rectangle 派生自 Shape

public class Shape
{
public double Width { get; set; }
public double Height { get; set; } public override string ToString()
{
return String.Format("Width: {0}, Height: {1}", Width, Height);
}
} public class Rectangle : Shape
{ }

参数类型协变

public void Display(Shape o)
{ } Rectangle r = new Rectangle{Width = , Height = };
Display(r);

泛型接口的协变

out关键字标注,泛型接口是协变,意味着返回类型只能是T。

接口IIndex 与 类型 T 是协变,并从制度索引器返回这个类型。

public interface IIndex<out T>
{
T this[int index] { get; }
int Count { get; }
}

实现接口

public class RectangleCollection : IIndex<Rectangle>
{
private Rectangle[] data = new Rectangle[]
{
new Rectangle { Height=, Width= },
new Rectangle { Height=, Width=},
new Rectangle { Height=4.5, Width=2.9}
}; private static RectangleCollection coll;
public static RectangleCollection GetRectangles()
{
return coll ?? (coll = new RectangleCollection());
} public Rectangle this[int index]
{
get
{
if (index < || index > data.Length)
throw new ArgumentOutOfRangeException("index");
return data[index];
}
}
public int Count
{
get
{
return data.Length;
}
}
}

coll ?? (coll = new RectangleCollection());

?? 合并运算符,如果 coll 为 null,将调用运算符的右侧。

static void Main(string[] args)
{
IIndex<Rectangle> rectangles = RectangleCollection.GetRectangles();
IIndex<Shape> shapes = rectangles; for (int i = ; i < shapes.Count; i++)
{
Console.WriteLine(shapes[i]);
}
}

泛型接口抗变

in 关键标注 泛型接口是抗变的

public interface IDisplay<in T>
{
void Show(T item);
}

使用Shape对象作为参数

public class ShapeDisplay : IDisplay<Shape>
{
public void Show(Shape s)
{
Console.WriteLine("{0} Width: {1}, Height: {2}", s.GetType().Name, s.Width, s.Height);
}
}
IDisplay<Shape> shapeDisplay = new ShapeDisplay();
IDisplay<Rectangle> rectangleDisplay = shapeDisplay;
rectangleDisplay.Show(rectangles[]);

在.NET中 参数类型是协变,返回值是抗变。

http://www.cnblogs.com/qionghua/archive/2012/08/02/2620486.html

泛型结构

public struct Nullable<T> where T:struct
{
public Nullable(T value)
{
this.hasValue = true;
this.value = value;
} private bool hasValue; public bool HasValue
{
get { return hasValue; }
} private T value; public T Value
{
get
{
if (!hasValue)
{
throw new InvalidOperationException("no value");
}
return value;
}
} public static explicit operator T(Nullable<T> value)
{
return value.Value;
} public static implicit operator Nullable<T>(T value)
{
return new Nullable<T>(value);
} public override string ToString()
{
if(!HasValue)
return String.Empty;
return this.value.ToString();
}
}
Nullable<int> x;
x = ;
x += ;
if (x.HasValue)
{
int y = x.Value;
}
x = null;

定义空类型值变量 使用 "?" 运算符

int? v2 = null;
if (v2 == null)
{
Console.WriteLine("x is null");
}
 static int? GetNullableType()
{
return null;
} static void Main(string[] args)
{
int? x1 = GetNullableType();
int? x2 = GetNullableType();
int? x3 = x1 + x2;
if (x3 == null)
{
Console.WriteLine("x3 is null");
}
}

类型转换

int y1 = ;
int? x1 = y1; // error 不能将null赋值给,非可空类型
x1 = null;
y1 = (int) x1; // 可以用合并运算符 提供默认值
y1 = x1 ?? ;

泛型方法

static void Swap<T>(ref T x, ref T y)
{
T temp;
temp = x;
x = y;
y = temp;
} static void Main(string[] args)
{
int i = ;
int j = ;
Swap<int>(ref j, ref i);
Console.WriteLine("i={0},j={1}",i,j);
}
public class Account
{
public string Name { get; set; }
public decimal Balance { get; private set; } public Account(string name, Decimal balance)
{
this.Name = name;
this.Balance = balance;
}
} static void Main(string[] args)
{
List<Account> accounts = new List<Account>()
{
new Account("xxxx1",),
new Account("xxxx2",),
new Account("xxxx3",),
new Account("xxxx4",)
}; decimal sum = AccumulateSimple(accounts);
Console.WriteLine("sum={0}",sum);
} public static decimal AccumulateSimple(IEnumerable<Account> source)
{
decimal sum = ;
foreach (Account account in source)
{
sum += account.Balance;
}
return sum;
}

IEnumerable 接口迭代集合元素。

约束的泛型方法

public class Account: IAccount
{
public string Name { get; set; }
public decimal Balance { get; private set; } public Account(string name, Decimal balance)
{
this.Name = name;
this.Balance = balance;
}
} public interface IAccount
{
decimal Balance { get; }
string Name { get; }
} public static decimal AccumulateSimple<TAccount>(IEnumerable<TAccount> source) where TAccount:IAccount
{
decimal sum = ;
foreach (TAccount account in source)
{
sum += account.Balance;
}
return sum;
} List<Account> accounts = new List<Account>()
{
new Account("xxxx1",),
new Account("xxxx2",),
new Account("xxxx3",),
new Account("xxxx4",)
}; decimal sum = AccumulateSimple(accounts);
Console.WriteLine("sum={0}",sum);

委托的泛型方法

 public static T2 AccumulateSimple<T1, T2>(IEnumerable<T1> source,Func<T1,T2,T2> action)
{
T2 sum = default(T2);
foreach (T1 item in source)
{
sum = action(item, sum);
}
return sum;
} decimal total = AccumulateSimple<Account,decimal>(accounts,(item,sum) => sum += item.Balance);
Console.WriteLine("sum={0}", total);

Lambda表达式 (item,sum) => sum += item.Balance

C# 泛型(4) 持续更新的更多相关文章

  1. java视频教程 Java自学视频整理(持续更新中...)

    视频教程,马士兵java视频教程,java视频 1.Java基础视频 <张孝祥JAVA视频教程>完整版[RMVB](东西网) 历经5年锤炼(史上最适合初学者入门的Java基础视频)(传智播 ...

  2. 《WCF技术剖析》博文系列汇总[持续更新中]

    原文:<WCF技术剖析>博文系列汇总[持续更新中] 近半年以来,一直忙于我的第一本WCF专著<WCF技术剖析(卷1)>的写作,一直无暇管理自己的Blog.在<WCF技术剖 ...

  3. ASP.NET MVC深入浅出系列(持续更新) ORM系列之Entity FrameWork详解(持续更新) 第十六节:语法总结(3)(C#6.0和C#7.0新语法) 第三节:深度剖析各类数据结构(Array、List、Queue、Stack)及线程安全问题和yeild关键字 各种通讯连接方式 设计模式篇 第十二节: 总结Quartz.Net几种部署模式(IIS、Exe、服务部署【借

    ASP.NET MVC深入浅出系列(持续更新)   一. ASP.NET体系 从事.Net开发以来,最先接触的Web开发框架是Asp.Net WebForm,该框架高度封装,为了隐藏Http的无状态模 ...

  4. Ext JS学习第十六天 事件机制event(一) DotNet进阶系列(持续更新) 第一节:.Net版基于WebSocket的聊天室样例 第十五节:深入理解async和await的作用及各种适用场景和用法 第十五节:深入理解async和await的作用及各种适用场景和用法 前端自动化准备和详细配置(NVM、NPM/CNPM、NodeJs、NRM、WebPack、Gulp/Grunt、G

    code&monkey   Ext JS学习第十六天 事件机制event(一) 此文用来记录学习笔记: 休息了好几天,从今天开始继续保持更新,鞭策自己学习 今天我们来说一说什么是事件,对于事件 ...

  5. iOS面试高薪,进阶 你会这些呢嘛?(持续更新中)

    这个栏目将持续更新--请iOS的小伙伴关注!做这个的初心是希望能巩固自己的基础知识,当然也希望能帮助更多的开发者! 基础>分析>总结 面试 iOS常见基础面试题(附参考答案) iOS底层原 ...

  6. SpringBoot面试题 (史上最全、持续更新、吐血推荐)

    文章很长,建议收藏起来,慢慢读! 疯狂创客圈为小伙伴奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 大厂必备 ...

  7. 神技!微信小程序(应用号)抢先入门教程(附最新案例DEMO-豆瓣电影)持续更新

    微信小程序 Demo(豆瓣电影) 由于时间的关系,没有办法写一个完整的说明,后续配合一些视频资料,请持续关注 官方文档:https://mp.weixin.qq.com/debug/wxadoc/de ...

  8. iOS系列教程 目录 (持续更新...)

      前言: 听说搞iOS的都是高富帅,身边妹子无数.咱也来玩玩.哈哈. 本篇所有内容使用的是XCode工具.Swift语言进行开发. 我现在也是学习阶段,每一篇内容都是经过自己实际编写完一遍之后,发现 ...

  9. ASP.NET MVC 5 系列 学习笔记 目录 (持续更新...)

    前言: 记得当初培训的时候,学习的还是ASP.NET,现在回想一下,图片水印.统计人数.过滤器....HttpHandler是多么的经典! 不过后来接触到了MVC,便立马爱上了它.Model-View ...

  10. git常用命令(持续更新中)

    git常用命令(持续更新中) 本地仓库操作git int                                 初始化本地仓库git add .                       ...

随机推荐

  1. DS博客大作业--树(李天明组)

    DS博客大作业--树 大作业博客要求 (10分) 1.树的存储结构说明 .树采用的是链式存储结构. .这段代码中定义了两个结构体.第一个是自定义为Name类型的结构体,里面的成员有字符串str和类型为 ...

  2. GitHub项目管理维护实用教程

    GitHub项目维护教程   1)注册GitHub账户并登陆: 2)在Windows cmd(或Ubuntu中的terminal)中cd到自己的工作目录,将仓库clone下来: 命令: git clo ...

  3. [转帖]centos7上设置中文字符集

    centos7上设置中文字符集 https://www.cnblogs.com/kaishirenshi/p/10528034.html author: headsen  chen date: 201 ...

  4. scrapy-redis数据去重与分布式框架

    数据去重 生成指纹:利用hashlib的sha1,对request的请求体.请求url.请求方法进行加密,返回一个40位长度的16进制的字符串,称为指纹 fp = hashlib.sha1() fp. ...

  5. DISCO Presents Discovery Channel Code Contest 2020 Qual Task E. Majority of Balls

    Not able to solve this problem during the contest (virtual participation). The first observation is ...

  6. if (strAreaCode.Find("体检")>=0)

    string类提供了6种查找函数,每种函数以不同形式的find命名. 这些操作全部返回string::size_type类型的值,以下形式标记查找匹配所发生的位置: 或者返回一个名为string::n ...

  7. 剑指offer40:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字

    1 题目描述 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字. 2 思路和方法 (1)异或:除了有两个数字只出现了一次,其他数字都出现了两次.异或运算中,任 ...

  8. docker 入门2 - 容器 【翻译】

    入门,第 2 部分:容器 先决条件 安装的 Docker 版本是 1.13 及以上. 读完 第一部分 用下面的命令快速测试你的环境是否完备: docker run hello-world 概述 现在开 ...

  9. Python利用PIL将数值矩阵转化为图像

    要求:输入一个n*n的矩阵,矩阵包括从-1到1的浮点数,将其转化为可视化图像 调库 from PIL import Image import numpy as np import math 载入图像, ...

  10. java lesson10homework

    1.    输入三个整数x, y, z,请把这三个数由小到大输出. 2.  package Homework10; 3.  //:类方法 4.  public class Sort { 5.  voi ...