C# 泛型(4) 持续更新
泛型可以创建独立于被包含类型的类和方法。
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) 持续更新的更多相关文章
- java视频教程 Java自学视频整理(持续更新中...)
视频教程,马士兵java视频教程,java视频 1.Java基础视频 <张孝祥JAVA视频教程>完整版[RMVB](东西网) 历经5年锤炼(史上最适合初学者入门的Java基础视频)(传智播 ...
- 《WCF技术剖析》博文系列汇总[持续更新中]
原文:<WCF技术剖析>博文系列汇总[持续更新中] 近半年以来,一直忙于我的第一本WCF专著<WCF技术剖析(卷1)>的写作,一直无暇管理自己的Blog.在<WCF技术剖 ...
- 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的无状态模 ...
- Ext JS学习第十六天 事件机制event(一) DotNet进阶系列(持续更新) 第一节:.Net版基于WebSocket的聊天室样例 第十五节:深入理解async和await的作用及各种适用场景和用法 第十五节:深入理解async和await的作用及各种适用场景和用法 前端自动化准备和详细配置(NVM、NPM/CNPM、NodeJs、NRM、WebPack、Gulp/Grunt、G
code&monkey Ext JS学习第十六天 事件机制event(一) 此文用来记录学习笔记: 休息了好几天,从今天开始继续保持更新,鞭策自己学习 今天我们来说一说什么是事件,对于事件 ...
- iOS面试高薪,进阶 你会这些呢嘛?(持续更新中)
这个栏目将持续更新--请iOS的小伙伴关注!做这个的初心是希望能巩固自己的基础知识,当然也希望能帮助更多的开发者! 基础>分析>总结 面试 iOS常见基础面试题(附参考答案) iOS底层原 ...
- SpringBoot面试题 (史上最全、持续更新、吐血推荐)
文章很长,建议收藏起来,慢慢读! 疯狂创客圈为小伙伴奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 大厂必备 ...
- 神技!微信小程序(应用号)抢先入门教程(附最新案例DEMO-豆瓣电影)持续更新
微信小程序 Demo(豆瓣电影) 由于时间的关系,没有办法写一个完整的说明,后续配合一些视频资料,请持续关注 官方文档:https://mp.weixin.qq.com/debug/wxadoc/de ...
- iOS系列教程 目录 (持续更新...)
前言: 听说搞iOS的都是高富帅,身边妹子无数.咱也来玩玩.哈哈. 本篇所有内容使用的是XCode工具.Swift语言进行开发. 我现在也是学习阶段,每一篇内容都是经过自己实际编写完一遍之后,发现 ...
- ASP.NET MVC 5 系列 学习笔记 目录 (持续更新...)
前言: 记得当初培训的时候,学习的还是ASP.NET,现在回想一下,图片水印.统计人数.过滤器....HttpHandler是多么的经典! 不过后来接触到了MVC,便立马爱上了它.Model-View ...
- git常用命令(持续更新中)
git常用命令(持续更新中) 本地仓库操作git int 初始化本地仓库git add . ...
随机推荐
- vue加载优化方案
我们的项目随着组件的加入,首次加载的js文件越来越大,用户等待时间越来越长:之前想着使用webpack的splitCoding来解决,看了webpack的官方文档可以配置optimization的 m ...
- 修改profile导致bash不能用的补救方法
输入这条命令:export PATH=/usr/bin:/usr/sbin:/bin:/sbin:/usr/X11R6/bin 由于shell命令基本都在/usr/bin,/usr/sbin,/bin ...
- JS获取URL地址
var url = window.location.href;
- [Arc102B]All Your Paths are Different Lengths_构造_二进制拆分
All Your Paths are Different Lengths 题目链接:https://atcoder.jp/contests/arc102/tasks/arc102_b 题解: 构造题有 ...
- Vue ---- Vuex 的第一次接触
在 Vue.js 的项目中,如果项目结构简单, 父子组件之间的数据传递可以使用 props 或者 $emit 等方式 http://www.cnblogs.com/wisewrong/p/62660 ...
- request方法
获取请求行方法: getMethod()获取请求的方法 getContextPath()回去虚拟路径 getServletPath()获取路径(只有在servert中使用) getQueryStrin ...
- xpath定位器
目录 什么是xpath? xpath的作用 xpath的术语 xpath语法 XPath 轴 XPath 运算符 xpath的优势 什么是xpath? 官方解释:XPath即为XML路径语言(XML ...
- DDD 理解
DDD提倡充血模型,业务放在类中,而不是服务中,刚开始是比较不清楚的.突然明白,以前开发桌面程序的时候,不就是这样处理了吗?业务分析和代码实现一一对应.因为桌面程序没有数据库,他就是纯粹的面向对象的实 ...
- 排查RabbitMQ安装错误
1.注册表中是否有 HKEY_LOCAL_MACHINE\SOFTWARE\Ericsson\Erlang\ErlSrv\1.1\RabbitMQ 此项.(须有) 2.安装目录是否存在中文.(不可有 ...
- 4、Wepy-Redux基本使用 参考自https://blog.csdn.net/baidu_32377671/article/details/86708019
摘抄自https://juejin.im/post/5b067f6ff265da0de02f3887 wepy 框架本身是支持 Redux 的,我们在构建项目的时候,将 是否安装 Redux 选择 y ...