1.泛型的概念

    C#中的泛型与C++中的模板类似,泛型是实例化过程中提供的类型或类建立的。泛型并不限于类,还可以创建泛型接口、泛型方法,甚至泛型委托。这将极大提高代码的灵活性,正确使用泛型可以显著缩短开发时间。与C++不同的是,C#中所有操作都是在运行期间进行的。

2.使用泛型

  • 可空类型

值类型必须包含一个值,它们可以在声明之后,赋值之前,在未赋值状态下存在,但不能以任何方式使用,而引用类型可以为null。有时让值类型为空是很有用的,泛型提供了使用System.Nullable<T>使值类型为空的一种方式。如下代码:

private Nullable<int> _nullableInt;

则可以为_nullableInt赋为null,如下:

_nullableInt = null;

可空类型非常有用,以致于C#中加入了语法:

int? _nullableIntSecond;

  • System.Collections.Generic 名称空间

    这个名称空间用于处理集合的泛型类型,使用的非常频繁。将以List<T>和Dictionary<K,V>为例介绍这些类,以及和它们配合使用的接口和方法。

1.List<T>

        List<T>泛型集合类更加快捷,更易于使用,创建T类型对象的集合需要一下方法:

List<string> _myCollection = new List<string>();

将创建T为String的List集合。

可以在代码中去查看List<T>所支持的方法,这里不再赘述。

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

对泛型列表进行排序和搜索与和其它列表进行排序和搜索是一样的,如下为实例代码:

public class NumberCollection : List<int>
{
public NumberCollection(IEnumerable<int> initialNums)
{
foreach (var num in initialNums)
{
Add(num);
}
} public NumberCollection()
{
for (int i=;i < ;++i)
{
Add(i);
}
} public void Print()
{
foreach (var num in this)
{
Console.WriteLine(num);
} Console.Read();
}
}
public static class NumberCollectionDelegate
{
public static int Compare(int i,int j)
{
if (i > j)
{
return -;
}
else if (i < j)
{
return ;
}
return ;
} public static bool Find(int i)
{
if (i % == )
{
return true;
} return false;
}

public static Comparison<int> CopmareDelegate = new Comparison<int>(Compare);


public static Predicate<int> Predicate = new Predicate<int>(Find);

    }
var numColleciton = new NumberCollection();
numColleciton.Print();
numColleciton.Sort(NumberCollectionDelegate.CopmareDelegate);
numColleciton.Print();
var newNumCollection = new NumberCollection(numColleciton.FindAll(NumberCollectionDelegate.Predicate));
newNumCollection.Print();
Console.ReadLine();

如上代码,首先定义了NumberCollection继承自List<int>,定义了Print方法用来输出集合中所有的值,类NumberCollectionDelegate中定义了Compare方法,以及Find方法,Compare方法用于对集合进行降序排序(为什么这么写是降序排序请关注另一篇文章),Find方法用于选择集合中为偶数的值。在实例的使用中,首先对集合中的元素进行了降序排序,后选择集合中为偶数的值组成新的集合,当然上述比较与查找用法可以简化为以下用法:

numColleciton.Sort(NumberCollectionDelegate.Compare);

var newNumCollection = new NumberCollection(numColleciton.FindAll(NumberCollectionDelegate.Find));

这样就不需要显示引用Comparison<int>类型了,但是在使用时仍然会隐式创建Comparison<int>实例,对于比较也是同样的。在许多情况下,都可以使用方法组以这种方式隐式的创建委托,使代码变的更容易读取。

3.Dictionary<K,V>

    这个类型可以定义键值对的集合,这个类型需要实例化两个类型,分别用于键和值,以表示集合中的各个项。可以使用强类型化的Add方法添加键值对,如下。

Dictionary<string, int> stringIntDictionary = new Dictionary<string, int>();
stringIntDictionary.Add("Tom", 1);
stringIntDictionary.Add("Lucy", 2);
stringIntDictionary.Add("Lily", 3);

可以直接访问Dicitionary中的keys和Values属性值:

foreach (var key in stringIntDictionary.Keys)
{
Console.WriteLine(key);
}

foreach (var value in stringIntDictionary.Values)
{
Console.WriteLine(value);
}

同样可以迭代集合中每一项,如下:

foreach (KeyValuePair<string,int> item in stringIntDictionary)
{
Console.WriteLine("{0} = {1}", item.Key, item.Value);
}

对于Dictionary<K,V>需要注意的一点是,每个项的键都必须式唯一的。如果要添加的项与已存在的项的键值相同,则会抛出异常。

3.定义泛型

    1.定义泛型类

         要创建泛型类,只需在类定义中包括尖括号:

class MyGenericClass<T>
{
}

其中T可以是任意标识符,只需要遵循C#命名规则即可,但一般只使用T。

泛型类可以在其定义中包含任意多个类型,它们用逗号分开,例如:

class MyGenericClass<T1,T2,T3>
{
}

定义了这些类型之后,就可以在类定义中像使用其它类型那样使用它们,如下

class MyGenericClass<T1,T2,T3>
{
private T1 _object; public MyGenericClass(T1 item)
{
_object = item;
} public T1 InnerT1Object
{
get
{
return _object;
}
}
}

注意不能假定使用了什么类型,例如:

_object = new T1();

因为此刻不知道T1是什么,也就不能使用它的构造函数,可能T1就没有构造函数,或者没有可公共访问的构造函数。因此要对泛型进行实际的操作需要更多了解其使用的类型。

  • default关键字

    要确定用于创建泛型类型的实例,需要了解一个最基本的情况,它是引用类型还是值类型,若不了解这个情况就不能直接对变量赋予null值。此时default关键字就派上了用场:

_object = default(T1);

如果_object是引用类型就给引用类型赋为null值,如果为值类型就给它赋为默认值。对于数字类型默认值为0,对于结构,按照相同的规则对它们进行赋值。default关键字允许对必须使用的类型进行更多的操作,为了进行更多的操作,必须对使用的类型进行更多的约束。

  • 约束类型

    前面使用的类型称为无绑定类型,因为没有对它们进行任何约束,而通过约束可以限定用于泛型的类型。在类定义中,可以使用where关键字,来限定用于泛型的类型,如下:

class MyGenericClass<T1,T2,T3> where T1 : constraint

其中constraint定义了约束,可以用这种能方式定义很多约束,每个约束之间用逗号分开。还可以使用多个where语句,定义泛型类型需要的任意类型或所有类型上的约束,约束必须出现在类型说明符的后面。

  • 从泛型类中继承

    类可以从泛型中继承,如

class Farm<T> : IEnumerable<T> where T : Animal
{
}

如上代码Farm<T>是一个接口类型,同样对于T的约束也会在IEnumerable中使用的T上添加一个额外的约束,这可以用于限制用于约束的类型,但是需要遵守一些规则。

首先,如果某个类型所继承的基类型中受到了约束,该类型就不能接触约束,即类型T在基类中使用时所受到的约束,必须扩展到子类中,至少于基类的约束相同。

  • 泛型运算符

    泛型类也支持运算符的重写。

  • 泛型结构

    结构与类相同,只是有一些细微的差别,而且结构是值类型,不是引用类型,所以可以创建泛型结构,如:

struct MyGenericStruct<T1, T2>
{
}

2.定义泛型接口

定义泛型接口于定义泛型类所用的技术相同,例如:

  interface IGeneric<T> where T : Object
{
void Sum(T x, T y);
}

3.定义泛型方法

    可以使用泛型方法以达到泛型方法的更一般形式,在泛型方法中,参数类型或返回类型由泛型类型参数所决定。

,例如:

  T GetDefault<T>()
{
return default(T);
}

可以使用非泛型类,实现泛型方法:

   public class Defaulter
{
public T GetDefault<T>()
{
return default(T);
}
}

如果类是泛型的,那么需要为类中的泛型方法提供不同的标示符。如下代码会提示泛型方法:

  public class Defaulter<T>
{
public T GetDefault<T>()
{
return default(T);
}
}

会提示内部泛型参数与外部泛型参数相同,此时应该更改泛型标示符。

本篇内容参考C#入门经典。

C#泛型编程的更多相关文章

  1. C++泛型编程:template模板

    泛型编程就是以独立于任何特定类型的方式编写代码,而模板是C++泛型编程的基础. 所谓template,是针对“一个或多个尚未明确的类型”所编写的函数或类. 使用template时,可以显示的或隐示的将 ...

  2. C语言的泛型编程

    1 问题引入 首先引入一个问题,实现一个泛型的swap函数,分别使用C++和C实现. 2 C++的泛型 C++有良好的泛型编程机制,所以我很快就写出了C++版的泛型swap函数. template&l ...

  3. c++ 泛型编程及模板学习

    泛型编程,英文叫做Generic programming 可以理解为,具有通用意义的.普适性的,编程. 比如,你要实现一个函数去比较两个数值的大小,数值可能是int或者string.初次尝试,我们直观 ...

  4. C++学习笔记26:泛型编程概念

    一.什么是泛型编程? 泛型就是通用的型式 编写不依赖数据对象型式的代码就是泛型编程 二.为什么需要泛型编程? 函数重载,相似类定义与型式兼容性 例如:设计函数,求两个数据对象的较小值 //未明确规定参 ...

  5. C++ STL泛型编程——在ACM中的运用

    学习过C++的朋友们应该对STL和泛型编程这两个名词不会陌生.两者之间的关系不言而喻,泛型编程的思想促使了STL的诞生,而STL则很好地体现了泛型编程这种思想.这次想简单说一下STL在ACM中的一些应 ...

  6. C++模板&泛型编程

    ---恢复内容开始--- 一.泛型编程 定义:编写与类型无关的逻辑代码,是代码复用的一种手段.模板是泛型编程的基础 模板分为:函数模板和类模板 函数模板:代表了一个函数家族,该函数与类型无关,在使用时 ...

  7. C语言实现泛型编程

    泛型编程让你编写完全一般化并可重复使用的算法,其效率与针对某特定数据类型而设计的算法相同.在C语言中,可以通过一些手段实现这样的泛型编程.这里介绍一种方法——通过无类型指针void* 看下面的一个实现 ...

  8. C++ 模板与泛型编程

    <C++ Primer 4th>读书笔记 所谓泛型编程就是以独立于任何特定类型的方式编写代码.泛型编程与面向对象编程一样,都依赖于某种形式的多态性. 面向对象编程中的多态性在运行时应用于存 ...

  9. atitit.泛型编程总结最佳实践 vO99 java c++ c#.net php

    atitit.泛型编程总结最佳实践 vO99 java c++ c#.net php \ 1. 泛型历史 1 由来 1 2. 泛型的机制编辑 1 机制 1 编译机制 2 3. 泛型方法定义1::前定义 ...

  10. C++泛型编程原理

    1.什么是泛型编程前面我们介绍的vector,list,map都是一种数据结构容器,容器本身的存储结构不同,各容器中存在的数据类型也可以不同.但我们在访问这些容器中数据时,拥有相同的方式.这种方式就叫 ...

随机推荐

  1. Zepto.js-事件处理

    http://www.webdevs.cn/article/68.html     web开发网 事件 $.Event $.Event(type, [properties]) ⇒ event 创建并初 ...

  2. jQuery 的 ready 函数是如何工作的?(源码分析)

    如果你使用过 jQuery , 就必然使用过 ready 函数,它用来注册当页面准备好之后可以执行的函数. 问题来啦,我们的页面什么时候准备好了呢? 1. onload 事件 最基本的处理方式就是页面 ...

  3. 选择移动web开发框架研究——有mui、frozenui以及Sencha Touch等

    纯粹的总结一下移动web开发框架,移动 web开发框架有jQuery Mobile .Sencha Touch等等,他们都来源于web开发,是成熟的框架,jQuery Mobile出自于jQuery家 ...

  4. http的Max-Forwards头的作用(转)

    请求头的Max-Forwards用来请求特定代理.当代理收到一个允许URI转发的OPTIONS请求,则检查Max-Forwards.如果Max-Forwards值为0,则不能转发该消息:相反,代理会将 ...

  5. HDU-1020-Encoding(水题,但题目意思容易搞错,英语的问题)

    题目链接 http://acm.hdu.edu.cn/webcontest/contest_showproblem.php?pid=1000&ojid=0&cid=7996&h ...

  6. hyperLink的定制

    在iReport中增加hyperLink,点击之后没有反应:需要重新写一遍net.sf.jasperreports.view.JRViewer; 修改其中的gotoHyperlink方法: case ...

  7. 分析器错误消息: 无法识别的属性“targetFramework”。

    配置错误 说明: 在处理向该请求提供服务所需的配置文件时出错.请检查下面的特定错误详细信息并适当地修改配置文件. 分析器错误消息: 无法识别的属性“targetFramework”.请注意属性名称区分 ...

  8. doubango(6)--Doubango协议栈中对RTP的管理

    相关数据结构 1.    tsip_dialog_invite_t 描述: 一个invite_dialog代表了一个invite期间的所有的信令流程,因此,它首先是一个普遍的dialog的特殊化结构, ...

  9. 关于MATSIM中,如何关闭自动加载dtd的问题

    有用过MATSIM做交通仿真的朋友应该都知道,在创建Scenario时,会默认加载matsim官网的netword的dtd文件,然后因为网络的问题,加载往往会报错,从而造成系统异常退出,如图所示: 根 ...

  10. 【js编程艺术】小制作五

    1.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <ti ...