1.泛型的概念

所谓泛型,即通过参数化类型来实现在同一份代码上操作多种数据类型。泛型编程是一种编程范式,它利用“参数化类型”将类型抽象化,从而实现更为灵活的复用。

2. .net提供的泛型

2.1可空类型System.Nullable<T>

简单类型和引用类型的一个区别是简单类型必须包含一个值,引用类型可以是null,有时候需要把简单类型设置为可空类型,比如在处理数据库数据的时候。可以使用System.Nullable<T>声明一个可空类型,如System.Nullable<int> nullableInt = null;可以通过判断可空类型是否为null或者判断HasValue是否为true确定可空类型是否为空,如

            System.Nullable<int> nullableInt = null;
if (nullableInt == null)
{
//
}
//等价于
if (nullableInt.HasValue)
{
//
}

可空类型缩写,因为可空类型比较常用,所以可以使用了一个比较简便的声明方式,可以在简单类型后面加个问号表示可以空类型,如int? op1=5

可空类型可以像简单类型一样使用+-*/等运算符来处理值,

int ? op1=
int ? op2=op1*;

简单类型可以隐式转换成可空类型,可空类型转换成简单类型必须使用显示转换..如下例子2会隐式转换成可空类型参与运算,运算结果强制转换成int类型。

int? op1=
int op2 =(int)op1*;

我们也可以通过可空类型的Value属性进行计算,但要判断是否有值,否则会引发异常

int? op1 = ;
if (op1.HasValue)
{
int op2 = op1.Value + ;
}

对于bool?之外的简单可空类型,如果运算式子中有一个为null,则计算结果为null

int? op1 = null;
int? op2 = op1 + ;//null

对于bool? 可以使用的运算符有&、|.他们的计算结果如下

op1 op2 op1&op2 op1|op2
true true true true
true false false true
true null null true
false true false true
false false false false
false null false null
null true null true
null false false null
null null null null

可以这样简单的记忆,对于&运算符有一个false则为false,不管有没有null,其他情况有null皆为null;

对于|相反,有一个true则为true,不管有没有null,其他情况有null皆为null。

2.2空接运算符??

int ?op1=;
int ? op2=op1*?? 等价于
int ? op1=;
int ? op2=op1*==null?:op1*;

如果??前面的表达式的值为null,则赋予??后面表达式的值赋给变量,否则把??前面表达式的值赋值给变量

3..net提供的泛型

3.1 List<T>

使用List<T>可以很轻易的创建自己想要的强类型集合,它的很多方法都已经自动实现了,不必像之前那样从CollectionBase继承,并实现对应的方法。

创建T类型的对象需要以下语法,T是我们使用的具体类型,比如string。

List<T> myCollection=new List<T>(); 

List<T>有3个构造函数,我们可以使用默认的构造函数,也可以传一个支持IEnumerable接口的集合,或者传入一个list的初始容量。

public List()
public List(IEnumerable<T> collection)
public List(int capacity)

List<T>支持的方法和属性:

成员 说明
int Count 返回集合中项的个数
void Add(T item ) 把一个项添加到集合中
void AddRange(IEnumerable <T>) 把多个项添加到集合中
IList<T> AsReadOnly 给集合返回一个只读接口
int Capacity 获取或者设置集合可以包含的项数。Capicity大于等于Count
void Clear() 清空所有项
bool Contains(T item) 确定项item是否包含在集合中
void CopyTo(T [] array,int index) 把集合复制到数组array中,从数组的索引index开始
IEnumerator<T>GetEnumerator() 获取一个IEnumerator<T>实例用于foreach循环。注意:返回的接口是强类型化为T的,所以不需要类型转换。
int Indexof(T item) 获取item的索引
int Insert(int index,T item) 在index位置插入item项
bool Remove(T item) 在集合中删除第一个item,并返回true,如果item不存在返回false
void RemoveAt(int index) 删除index位置的项

List<T>还有一个Item属性,允许List<T>像数组那样用下标进行访问

T item=myCollectionOfT[2];

List<T>例子

    class Animal
{
public string name;
public Animal(string name)
{
this.name = name;
} public void Feed()
{
Console.WriteLine("{0} has been Feeded.", this.name);
}
}
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{ List<Animal> list = new List<Animal>();
Animal a = new Animal("Rock");
Animal b = new Animal("Peter");
Animal c = new Animal("Tom");
list.Add(a);
list.Add(b);
list.Add(c);
list.Add(a); foreach (Animal o in list)
{
o.Feed();
} Console.WriteLine(list.IndexOf(a));//返回第一个a的索引,如果集合未包含a返回-1 list.Remove(a);//删除第一个a
Console.WriteLine(list.IndexOf(a));
Console.WriteLine("删除后");
foreach (Animal o in list)
{
o.Feed();
} Console.WriteLine("Count:{0},Capacity:{1}", list.Count, list.Capacity);
Console.ReadLine();
}
}

 3.2对泛型列表进行排序和搜索

对泛型列表进行排序和其他列表是一样的,其他列表,比如ArrayList可以通过IComparable、IComparer接口进行排序,泛型列表可以通过实现IComparable<T>,IComparer<T>进行排序,唯一的区别在于IComparable<T>,IComparer<T>是强类型化的,它只针对特定类型进行排序。下表列出了他们的区别:

泛型方法 非泛型方法 区别
int IComparable<T>.CompareTo(T otherObj) int IComparable.CompareTo(object obj) 泛型版本是强类型化的
int IComparer<T>.CompareTo(T otherObj) int IComparer.CompareTo(object obj) 泛型版本是强类型化的
 //实现IComparable<Vector>的好处是比较时传入参数是强类型化的,不用类型转换
class Vector:IComparable,IComparable<Vector>
{
public double? R = null;//大小
public double? Theta = null;//方向,单位度 //弧度
public double? ThetaRadians
{
//度和弧度转换180度=pi弧度,
get
{
return (Theta * Math.PI / );
}
} public Vector(double? r, double? theta)
{
if (r < )
{
r = -r;
theta += ;
} Theta = theta % ;
R = r;
} public override string ToString()
{
string rString = R.HasValue ? R.ToString() : "null";
string thetaString = Theta.HasValue ? Theta.ToString() : "null";
return string.Format("{0},{1}",rString,thetaString);
} public int CompareTo(object obj)
{
if (this.R > ((Vector)obj).R)
return -;
else if (this.R < ((Vector)obj).R)
return ;
return ;
} public int CompareTo(Vector other)
{
if (this.R > other.R)
return ;
else if (this.R < other.R)
return -;
return ;
} } class Vectors:List<Vector>
{
public Vectors()
{ } public Vectors(IEnumerable<Vector> initialItem)
{
AddRange(initialItem);
}
} class VectorDelegates
{
public static int Compare(Vector x, Vector y)
{
if (x.R > y.R)
return ;
else if (x.R < y.R)
return -;
return ; } public static bool TopRightQuadrant(Vector target)
{
if (target.Theta >= 0.0 && target.Theta <= 90.0)
return true;
else
return false;
}
} class VectorComparer :IComparer,IComparer<Vector>
{
public static VectorComparer Default= new VectorComparer(); public int Compare(object x, object y)
{
return (int)(((Vector)x).Theta-((Vector)y).Theta);
} public int Compare(Vector x, Vector y)
{
return (int)(x.Theta-y.Theta);
}
} class Program
{ static void Main(string[] args)
{
Vectors route = new Vectors();
route.Add(new Vector(2.0, 90.0));
route.Add(new Vector(1.0, 180.0));
route.Add(new Vector(0.5, 45.0));
route.Add(new Vector(2.0, 90.0));
route.Add(new Vector(2.5, 315.0)); //使用Vector默认的比较方法排序,如果同时实现了IComparable,IComparable<Vector>两个接口,比较时优先使用强类型化的方法
//所以以下排序会使用public int CompareTo(Vector other)方法而不是public int CompareTo(object obj)排序
route.Sort(); Console.WriteLine("默认排序,按大小降序");
foreach (Vector v in route)
{
Console.WriteLine(v.ToString());
} Console.WriteLine("使用泛型委托排序,按大小升序");
Comparison<Vector> sorter = new Comparison<Vector>(VectorDelegates.Compare);
route.Sort(sorter);
foreach (Vector v in route)
{
Console.WriteLine(v.ToString());
} Console.WriteLine("使用IComparer<T>接口排序,按角度大小升序");
route.Sort(VectorComparer.Default);
foreach (Vector v in route)
{
Console.WriteLine(v.ToString());
} Console.WriteLine("恢复默认排序后使用IComparer<T>接口,对前面三项排序,按角度大小升序");
route.Sort();
route.Sort(, , VectorComparer.Default);
foreach (Vector v in route)
{
Console.WriteLine(v.ToString());
} Console.WriteLine("使用泛型委托Predicate<T>查找所有角度在0到90之间的向量");
Predicate<Vector> searcher = new Predicate<Vector>(VectorDelegates.TopRightQuadrant);
Vectors topRightQuadrant =new Vectors( route.FindAll(searcher));
foreach (Vector v in topRightQuadrant)
{
Console.WriteLine(v.ToString());
} route[].CompareTo(route[]); Console.ReadLine();
}
}

除了使用泛型接口IComparable<T>和IComparer<T>对泛型列表进行排序,上面的例子中还使用了泛型委托Comparison<T>对集合排序,它的定义如下

public delegate int Comparison<in T>(T x, T y);

它表示一个返回类型为int ,有两个T类型参数的委托,使用时要传入一个方法签名一样的方法

还可以使用泛型委托Predicate<in T>查找符合条件的项,它的定义如下

public delegate bool Predicate<in T>(T obj);

 3.3Dictionary<K,V>

使用Dictionary<k,v>可以创建类型为k,和V的键值对集合,实例化之后可以像继承自DictionaryBase的类那样执行相同的操作。添加到接口Dictionary<k,v>的键必须唯一,否则会抛出ArgumentException异常。一般情况下,如果K是简单类型,比如int,string会判断值是否相等,如果是引用类型(除string)会判断两个对象的引用是否相等。如果要改变判断的规则可以给构造函数传入一个IEqualityComparer<TKey> comparer接口对象,如下使用不区分大小写的方法比较字符串

Dictionary<string, int> things = new Dictionary<string, int>(StringComparer.CurrentCultureIgnoreCase);

对于自己的类,我们可以继承IEqualityComparer<T>接口改变判断规则,IEqualityComparer<T>有两个比较方法,一般情况下先使用int GetHashCode(T obj)方法判断,如果两个比较对象返回值是相等的,则进一步用bool Equals(T x, T y)方法判断两个对象是否相等。

    // 摘要:
// 定义方法以支持对象的相等比较。
//
// 类型参数:
// T:
// 要比较的对象的类型。
public interface IEqualityComparer<in T>
{
// 摘要:
// 确定指定的对象是否相等。
//
// 参数:
// x:
// 要比较的第一个类型为 T 的对象。
//
// y:
// 要比较的第二个类型为 T 的对象。
//
// 返回结果:
// 如果指定的对象相等,则为 true;否则为 false。
bool Equals(T x, T y);
//
// 摘要:
// 返回指定对象的哈希代码。
//
// 参数:
// obj:
// System.Object,将为其返回哈希代码。
//
// 返回结果:
// 指定对象的哈希代码。
//
// 异常:
// System.ArgumentNullException:
// obj 的类型为引用类型,obj 为 null。
int GetHashCode(T obj);
}

只用int GetHashCode(T obj)判断的情况,如下例子中,我们创建两个同名的Animal对象,但是这两个对象属于不同的引用,obj.GetHashCode()返回的是不同的值,所以不管Equals方法怎么实现,程序都会认为cow和cow2是两个不同的对象。

    class Animal
{
protected string name;
public string Name
{
get { return name; }
set { name = value; }
} public Animal()
{
name = "The animal has no name.";
} public Animal(string newName)
{
name = newName;
} public void Feed()
{
Console.WriteLine("{0}has been fed.", name);
} } class AnimalComparer : IEqualityComparer<Animal>
{
public static AnimalComparer Default = new AnimalComparer(); public bool Equals(Animal x, Animal y)
{
if (Comparer.Default.Compare(x.Name, y.Name) == )
return true;
else
return false; //return x == y;
} public int GetHashCode(Animal obj)
{
return obj.GetHashCode();
}
} class Program
{ static void Main(string[] args)
{ Dictionary<Animal, int> a = new Dictionary<Animal, int>(AnimalComparer.Default);
Animal cow = new Cow("cow");
Animal cow2 = new Cow("cow"); a.Add(cow, );
a.Add(cow2, ); Console.ReadLine();
}
}

两个方法都使用的情况,我们把GetHashCode方法稍微改一下,同名的对象返回相同的值,此时调试发现,程序比较GetHashCode完方法之后又用Equals方法进行了比较,因为两次比较是相同的,所以添加cow2时程序报错

    class Animal
{
protected string name;
public string Name
{
get { return name; }
set { name = value; }
} public Animal()
{
name = "The animal has no name.";
} public Animal(string newName)
{
name = newName;
} public void Feed()
{
Console.WriteLine("{0}has been fed.", name);
} } class AnimalComparer : IEqualityComparer<Animal>
{
public static AnimalComparer Default = new AnimalComparer(); public bool Equals(Animal x, Animal y)
{
if (Comparer.Default.Compare(x.Name, y.Name) == )
return true;
else
return false; //return x == y;
} public int GetHashCode(Animal obj)
{
return obj.Name.GetHashCode();
}
}
static void Main(string[] args)
{ Dictionary<Animal, int> a = new Dictionary<Animal, int>(AnimalComparer.Default);
Animal cow = new Animal("cow");
Animal cow2 = new Animal("cow"); a.Add(cow, );
a.Add(cow2, ); Console.ReadLine();
}

我们还可以给构造函数传递一个支持IDictionary<K,V>的集合,或者指定集合的大小Capacity,Dictionary<k,v>有以下构造函数,可以根据情况使用

可以使用集合的Keys和Values属性迭代集合中的键和值,也可以使用KeyValuePair<K,V>迭代集合中的每个项,使用Dictionary[K]访问对象某项的值

    class Program
{ static void Main(string[] args)
{ Dictionary<Animal, int> a = new Dictionary<Animal, int>();
Animal cow = new Animal("cow");
Animal cow2 = new Animal("cow"); a.Add(cow, );
a.Add(cow2, ); foreach (Animal k in a.Keys)
{
Console.WriteLine(k.Name);
} foreach (int v in a.Values)
{
Console.WriteLine(v);
} foreach (KeyValuePair<Animal,int> d in a)
{
Console.WriteLine(d.Value);
} int value = a[cow];
Console.ReadLine();
}
}

19.C# 泛型的更多相关文章

  1. C++ Primer 学习笔记_45_STL实践与分析(19)--泛型算法的结构

    STL实践与分析 --泛型算法的结构 引言: 正如全部的容器都建立在一致的设计模式上一样,算法也具有共同的设计基础. 算法最主要的性质是须要使用的迭代器种类.全部算法都指定了它的每一个迭代器形參可使用 ...

  2. 【C#4.0图解教程】笔记(第19章~第25章)

    第19章 泛型 1.泛型概念 泛型提供了一种更准确地使用有一种以上的类型的代码的方式. 泛型允许我们声明类型参数化的代码,我们可以用不同的类型进行实例化. 泛型不是类型,而是类型的模板.   2.声明 ...

  3. lua迭代器和泛型for浅析

    (一) 首要概念要理清: 1. 在lua中,函数是一种"第一类值",他们具有特定的词法域."第一类值"表示在lua中函数与其他传统类型的值(例如数字和字符串)具 ...

  4. Step By Step(Lua迭代器和泛型for)

    Step By Step(Lua迭代器和泛型for) 1. 迭代器与Closure:    在Lua中,迭代器通常为函数,每调用一次函数,即返回集合中的"下一个"元素.每个迭代器都 ...

  5. C#温故知新:《C#图解教程》读书笔记系列

    一.此书到底何方神圣? 本书是广受赞誉C#图解教程的最新版本.作者在本书中创造了一种全新的可视化叙述方式,以图文并茂的形式.朴实简洁的文字,并辅之以大量表格和代码示例,全面.直观地阐述了C#语言的各种 ...

  6. 完美C++(第5版)(双色)

    完美C++(第5版)(双色) 薛正华 沈庚 韦远科 译 ISBN 978-7-121-23198-8 2014年6月出版 定价:148.00元 788页 16开 内容提要 <完美C++(第5版) ...

  7. .NET基础笔记(C#)

    闲着没事就把以前学习时的笔记拿出来整理了一下,个人感觉有点用,就想拿出来跟园友共享一下.有些基础性的内容比如基本概念.语法什么的就不发了. 内容:1.构造方法(函数) 2.继承   3.访问修饰符   ...

  8. Javaweb学习笔记——(七)——————myexlipse基本使用、jdk5.0新特性及反射讲解

    1.debug调试模式: *使用这种模式,调试程序(看到程序运行停止在这一行) -显示出来行号 -双击左边,出现一个圆点,表示设置了一个断点 *使用debug as方式,运行程序 -特使是否进入到调试 ...

  9. JavaWeb(HTML +css+js+Servlet....)

    注意 1.不要把函数命名为add(),不然容易和自带的冲突报错 2.是createElement 不要把create中的e写掉了 3.记得是getElementsByTaxName和getElemen ...

随机推荐

  1. 利用ApplicationContextAware装配Bean

    @Component public class SpringUtil implements ApplicationContextAware { private static ApplicationCo ...

  2. windows和linux换行规则的区别

    在计算机还没有出现之前,有一种叫做电传打字机(Teletype Model 33)的玩意,每秒钟可以打10个字符.但是它有一个问题,就是打完一行换行的时候,要用去0.2秒,正好可以打两个字符.要是在这 ...

  3. python数据类型——数据转换

    数据类型有很多种,比如数值和字符,比如6和a,字符是需要加双引号的,下面的例子运行的结果是不一样的,数值会相加而字符会相连 print(6+6)print("6"+"6& ...

  4. 译:Dataiku 白皮书之《在银行和保险行业应用数据科学》

    原文链接:Data Science For Banking & Insurance 如果不能正常访问,请点击备份获取. 在银行和保险行业应用数据科学 互联网巨头和金融技术创业时代的求生和发展 ...

  5. 执行Python出现LookupError: unknown encoding: cp65001解决办法

    执行Python出现LookupError: unknown encoding: cp65001错误 dos下执行以下命令即可 chcp 以上.

  6. Metasploit学习记录---Nessus安装部署

    1.Nessus介绍 nessus是目前世界上最为流行的漏洞扫描器之一.她提供完整的电脑漏洞扫描服务,并随时更新其漏洞数据库.Nessus不同于传统的漏洞扫描软件,可同时在本机或远端上遥控,进行系统的 ...

  7. 洛谷P1379 八数码难题

    传送门 1.先用dfs枚举9!的全排列,存到hash数组里(类似离散化),因为顺序枚举,就不需要排序了 2.朴素bfs,判重就用二分找hash:如果发现当前状态=要求状态,输出步数结束程序 上代码 # ...

  8. ubantu16.04安装ns2.34 错误

    把ns2.34解压缩之后,sudo ./install 出现的错误: 错误一:安装NS2.34过程中出现如下的错误:tools/ranvar.cc: In member function ‘virtu ...

  9. [jzoj]3875.【NOIP2014八校联考第4场第2试10.20】星球联盟(alliance)

    Link https://jzoj.net/senior/#main/show/3875 Problem 在遥远的S星系中一共有N个星球,编号为1…N.其中的一些星球决定组成联盟,以方便相互间的交流. ...

  10. js高级的2

    BOM0级事件元素绑定多个click最后只执行最后一个click. DOM2级事件元素绑定多个click,都要执行 注意当绑定的多个事件名,函数名,事件发生阶段三者完全一样时,才执行最后一个 div. ...