C# 泛型编程
来源:互联网 发布:mud游戏编程 百度云 编辑:程序博客网 时间:2024/05/29 19:28
为什么使用泛型
- 内存的分配:在堆中分配内存空间来存放复制的实际数据
- 完成实际数据的赋值:将值类型实例的实际数据复制到新分配的内存中。
- 地址返回:将堆中的独享地址返回给引用类型变量
拆箱:将引用类型转换成值类型
- 检查实例:首先检查进行拆箱操作的引用类型是否为null,如果为null就抛出异常,如果不为null则继续检查变量是否和拆箱后的类型是同一类型。 注意:被装箱过的数据才可以拆箱
地址返回:返回已装箱变量的实际数据部分的地址
数据复制:将堆中实际数据复制到栈中
class Program { public static void Main() { string a="hello"; fun(ref a);//按引用进行传递,传递的是a的地址,在函数中通过形参str直接修改实参a; Console.WriteLine(a); } public static void fun(ref string str) { str="world";//如果不按引用传递,改变的是引用的指向,并没有影响实参 } }
out 关键字 在使用时out声明的形参必须赋初值,out就是讲方法中的值带回到主函数中,将值赋值给形参public static void Main() { int a=10; fun(out a);//out 关键字,必须要通过形参给实参做赋值操作 Console.WriteLine(a); } public static void fun(out int n) { //Console.WriteLine(n); n = 100;//out关键字声明的形参必须要先初始化才能操作 Console.WriteLine(n); }
这是简单的变量的装箱拆箱操作,下面说一下方法
普通的方法中,定义的参数是什么类型就只能传递什么类型的参数。
首先 定义的是什么类型的数组就存什么类型
public void add(int v){ array[size++]=v; //这样就只能添加int类型的数据}然后你会想到用一个通用的类型数据objectpublic void add(object v){array[size++]=v;}使用object可以解决数据类型的问题,但是在会出现装箱、拆箱操作,这将在堆上分配和回收大量的变量,若数据量大,性能会
损失非常严重,在处理引用类型时虽然没有装箱和拆箱操作,但是将数据类型的强制转换操作,增加处理器的负担。
这里就可以使用一段代码测试一下统计一下两种操作的时间。(直接复制下来在你的机器上运行一下)
using System;using System.Diagnostics;//统计时间的命名空间namespace aa{ class Program { public static void Main() { int max = 10000000; Vector1 v1 = new Vector1(max); Stopwatch watch1 = new Stopwatch(); watch1.Start(); for (int i = 0; i < max; i++) { v1.add(i); } watch1.Stop(); TimeSpan span1 = watch1.Elapsed; Console.WriteLine("{0}:{1}",span1.Seconds,span1.Milliseconds); Vector2<int> v2 = new Vector2<int>(max); Stopwatch watch2 = new Stopwatch(); watch2.Start(); for (int i = 0; i < max; i++) { v2.add(i); } watch2.Stop(); TimeSpan span2 = watch2.Elapsed; Console.WriteLine("{0}:{1}",span2.Seconds,span2.Milliseconds); } } public class Vector1 { private object []arrary; private int size; public Vector1(int n) { arrary = new object[n]; size = 0; } public object this[int index] { get{ return arrary[index];} set{ arrary[index] = value;} } public void add(object obj) { arrary[size++] = obj; } } public class Vector2<T> { private T[]arr; private int size; public Vector2(int n) { arr = new T[n]; size = 0; } public T this[int index] { get{ return arr[index];} set{ arr[index] = value;} } public void add(T x) { arr[size++] = x; } }}使用泛型的优点
使用泛型就可以有传递多种类型的参数,减少了相同方法的重复定义。不仅可以解决类型问题还可以很大程度的优化性能
Vector<int> v1 = new Vector<int>(5); for (int i = 0; i < 5; i++) { v1.add(i); } for (int i = 0; i < 5; i++) { Console.WriteLine(v1[i]); } Vector<double> v2 = new Vector<double>(5); for (int i = 0; i < 5; i++) { v2.add(i * 1.1d); Console.WriteLine(v2[i]); }1.他是类型安全的,实例化了int 类型的栈,就不能处理string类型,其他数据类型也是一样
2.无需装箱和拆箱。这个类在实例化时,按照所传入的数据类型生成本地代码,本地代码类型已经确定,所以无需装箱和拆箱。
3.无需类型转换。
4.泛型将方法实现行为与方法操作的数据类型分离,实现了代码重用。
泛型中的两个容器
- List<>容器
List<>容器中每个元素都对应着一个整型下标。自己创建容器时都要自己定义一个长度,但是list容器不需要我们自己传递参数
系统会自动为我们定义,并且会自动扩展容量(List中包含多个属性和方法自己在编辑器中查看就行)
2.Dictionary 容器 以键值对的形式存储数据
每个元素(值)都对应着一个下标(键)。包含两个类型 键的类型和值的类型
foreach(KeyValuePair<string,int>i in d) 使用这样的方式遍历字典中的数据
Dictionary<string ,int> d = new Dictionary<string, int>(); //通过键来访问对应的值 for (int i = 0; i < 5; i++) { d.Add("hel" + i, i); } for (int i = 0; i < 5; i++) { Console.WriteLine(d["hel"+i]); }public class Channel { //这个是Channel的标题 private string tittle; //创建了一个存放News 的字典 private Dictionary<string,News>newsList; //创建一个索引,就可以通过channel对象直接访问 channel c1["aaa"]直接访问 //不用再使用c1.newslist["aaa"]; public News this[string index] { get{ return newsList[index];} set{ newsList[index] = value;} } public Channel(string _tittle) { tittle = _tittle; newsList = new Dictionary<string, News>(); } //调用系统的add方法将新闻添加到newslist中,然后每一个channel中都有一个词典, public void addNews(News n) { newsList.Add(n.Tittle, n); } }泛型方法,缩小了泛型的定义,只在方法中使用泛型
另外T只是一个表示符,可以使用其他的字母,不是非得使用T ,只是T 已经成了一种公认的习惯
泛型约束
首先要知道,泛型在没有约束的情况下可以指向任何数据类型泛型约束
通过where关键字给T添加约束
基类约束,指定是某个类或该类的子类,约束后,T的类型必须是该类型或者该类型的子类
1.基类约束public class Vector<T> where T:Person{}2.接口约束
给T 指定了类型必须继承接口中所有的方法
只有继承了接口了的实体类才能作为泛型参数
3.new()构造函数约束
允许开发人员实例化一个泛型类型的对象new()约束要求类型实参必须提供一个无参数的公有构造函数。使用new()约束时,
可以通过调用该无参数的构造函数来创建对象。
(1) new()约束可以与其他约束一起使用,但必须位于约束列表的末端。
(2) 仅允许使用无参的构造函数创建对象,即使同时存在其他的构造函数也是如此
(3) 不可以同时使用new()约束和值类型约束。因为值类型都隐式的提供了一个无参公共构造函数。
4.引用类型约束
where T:class 这时T 必须是引用类型
5.值类型约束
where T :struct 这是T必须是值类型。
不能同时出现的约束类型
不能同时出现的约束:基类约束,值类型约束、引用类型约束构造函数和值类型不能一起用
多个约束时的顺序顺序 第一位(基类型约束,值类型约束,引用类型约束)第二位 接口约束 第三位 构造函数约束
泛型接口
泛型接口,在继承接口时就要确定接口的类型
public interface IAdd<T> { void add(T x); } public class Vector1:IAdd<int>//接口继承前要指定泛型参数 {
}
泛型接口中的泛型参数可以使用泛型类中的参数
public class Vector2<T>:IAdd<T>{ }
泛型委托
public delegate T Mydelegate<T> (T x,T y);
泛型委托的优点在于,他允许开发人员以类型安全的方式定义一种通用形式,可用于匹配任意兼容的方法
泛型方法重载,参数类型一样时就会出现问题,因为方法名一样,参数列表也一样
泛型方法中的泛型参数和类中的泛型参数是没有关系的可以不一致- C#泛型编程
- C#泛型编程
- C#泛型编程
- c# 泛型编程
- c# 泛型编程
- C#泛型编程
- C#泛型编程
- C# 泛型编程
- C#泛型编程
- C# 泛型编程
- C#泛型编程
- C#泛型编程
- C#泛型编程
- C#泛型编程
- C#泛型编程
- C#泛型编程
- C#泛型编程
- C#泛型编程
- Haproxy+多台MySQL从服务器(Slave) 实现负载均衡
- Selenium~自动化测试来了
- 企业搜索引擎实战开发
- oracle的表名、字段名、constraint名的长度限制分别是多少?
- JDBC连接数据库
- C# 泛型编程
- Java程序员从笨鸟到菜鸟全部博客目录
- UE4之SaveGame重要节点
- AB1601低功耗注意事项
- Android中通信协议大全
- Java-多线程框架Executor解读
- 项目——通过自动回复机器人学Mybatis(二)
- pop 3368 Frequent values
- hadoop自带wordcount代码详解