摘要:本文介绍了如何定义一个C#泛型类,以及实现泛型类的继承、方法和约束。

C#泛型参数化了类型,把类型作为参数抽象出来,从而使我们在实际的运用当中能够更好的实现代码的重复利用,同时它提供了更强的类型安全,更高的效率,不过在约束方面,它只支持显示的约束,这样在灵活性方面就显得不是那么好了。我觉得它之所以能够提供更高的效率是因为泛型在实例化的时候采用了"on-demand"的模式,即按需实例化,发生在JIT(Just In Time)编译时。

下面来看如何定义一个C#泛型类,很简单,你只需要意识到一点,在这里,类型已经被参数化了:

using System;
using System.Collections.Generic;
using System.Text; namespace GenericTest
{
class Program
{
static void Main(string[] args)
{
//使用string,int来实例化Test< T,S>类
Test<string, int> t = new Test<string, int>("SHY520", ); //调用泛型类中的方法
t.SetValue();
}
} /**/
/// < summary>
/// 定义一个泛型类,该类有两个类型参数,分别是T,S
/// http://www.cnblogs.com/jara
/// < /summary>
/// < typeparam name="T">类型参数< /typeparam>
/// < typeparam name="S">类型参数< /typeparam>
public class Test<T, S>
{
//泛型类的类型参数可用于类成员
private T name;
private S age; public Test(T Name, S Age)
{
this.name = Name;
this.age = Age;
} public void SetValue()
{
Console.WriteLine(name.ToString());
Console.WriteLine(age.ToString());
}
}
}

上面的例子不是很恰当,目的是让初学泛型的你了解一下泛型的定义及实例化方法,如上,我们定义了一个泛型类,那么如何实现C#泛型类的继承呢?这里需要满足下面两点中的任何一点即可:

1、泛型类继承中,父类的类型参数已被实例化,这种情况下子类不一定必须是泛型类;

2、父类的类型参数没有被实例化,但来源于子类,也就是说父类和子类都是泛型类,并且二者有相同的类型参数;

//如果这样写的话,显然会报找不到类型T,S的错误
public class TestChild : Test< T, S> { } //正确的写法应该是
public class TestChild : Test< string, int>{ }
public class TestChild< T, S> : Test< T, S> { }
public class TestChild< T, S> : Test< String, int> { }

接着我们来看看泛型接口,其创建以及继承规则和上面说的泛型类是一样的,看下面的代码:

public interface IList<T>
{
T[] GetElements();
}
public interface IDictionary<K, V>
{
void Add(K key, V value);
} // 泛型接口的类型参数要么已实例化
// 要么来源于实现类声明的类型参数
class List<T> : IList<T>, IDictionary<int, T>
{
public T[] GetElements() { return null; }
public void Add(int index, T value)
{ }
}

在来看一下C#泛型委托,首先我们定义一个类型参数为T的委托,然后在类中利用委托调用方法:

using System;
using System.Collections.Generic;
using System.Text; namespace GenericTest
{
//定义一个委托,类型参数为T,返回值类型T
//泛型委托支持在返回值和参数上应用类型参数
delegate string GenericDelete<T>(T value); class test
{
static string F(int i) { return "SHY520"; }
static string G(string s) { return "SHY520"; } static void Main(string[] args)
{
GenericDelete<string> G1 = G;
GenericDelete<int> G2 = new GenericDelete<int>(F);
}
}
}

我们再来看C#泛型方法,C#的泛型机制只支持在方法申明上包含类型参数,也即是泛型方法。特别注意的是,泛型不支持在除了方法以外的其他类/接口成员上使用类型参数,但这些成员可以被包含在泛型类型中,并且可以使用泛型类型的类型参数。还有一点需要说的就是,泛型方法可以在泛型类型中,也可以存在于非泛型类型中。下面我们分别看一下泛型类型的申明,调用,重载和覆盖。

using System;
using System.Collections.Generic;
using System.Text; namespace GenericTest
{
class GenericClass
{
//申明一个泛型方法
public T getvalue<T>(T t)
{
return t;
} //调用泛型方法
//注意:在调用泛型方法时,对泛型方法的类型参数实例化
public int useMethod()
{
return this.getvalue<int>();
} //重载getvalue方法
public int getvalue(int i)
{
return i;
}
} //下面演示覆盖
//要注意的是,泛型方法被覆盖时,约束被默认继承,不需要重新指定约束关系
abstract class Parent
{
public abstract K TEST<K, V>(K k, V v) where K : V;
} class Child : Parent
{
public override T TEST<T, S>(T t, S s)
{
return t;
}
}
}

最后我们来看一下C#泛型中的约束:

C#中的泛型只支持显示的约束,因为这样才能保证C#所要求的类型安全,但显示的约束并非时必须的,如果不加约束,泛型类型参数将只能访问System.Object类型中的公有方法。“显式约束”由where子句表达,可以指定“基类约束”,“接口约束”,“构造器约束”,“值类型/引用类型约束”共四种约束。下面的例子来源于李建忠老师的讲座PPT。

1、基类约束:

class A { public void F1() {} }
class B { public void F2() {} }
class C< S,T>
where S: A // S继承自A
where T: B // T继承自B
{
 // 可以在类型为S的变量上调用F1,
 // 可以在类型为T的变量上调用F2
}

2、接口约束

interface IPrintable { void Print(); }
interface IComparable< T> { int CompareTo(T v);}
interface IKeyProvider< T> { T GetKey(); }
class Dictionary< K,V>
where K: IComparable< K>
where V: IPrintable, IKeyProvider< K>
{
 // 可以在类型为K的变量上调用CompareTo,
 // 可以在类型为V的变量上调用Print和GetKey
}

3、构造器约束

class A { public A() { } }
class B { public B(int i) { } }
class C< T>
where T : new()
{
 //可以在其中使用T t=new T();
}
C< A> c=new C< A>(); //可以,A有无参构造器
C< B> c=new C< B>(); //错误,B没有无参构造器

4、值/引用类型约束

public struct A { }
public class B { }
class C< T>
where T : struct
{
 // T在这里面是一个值类型
}
C< A> c=new C< A>(); //可以,A是一个值类型
C< B> c=new C< B>(); //错误,B是一个引用类型

浅谈C#泛型的定义、继承、方法和约束的更多相关文章

  1. 【ASP.NET MVC系列】浅谈表单和HTML辅助方法

    [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作篇)(下) [04]浅谈ASP. ...

  2. 浅谈Java——泛型DAO

    首先解释一下为什么要学习泛型DAO.平时在写DAO的时候是一个接口对应一个实现类,实现类里面要写很多的操作数据库的方法.当我们有很多的javaben的时候我们会写很多的接口和实现类,并且里面的代码都是 ...

  3. 浅谈Vue响应式(数组变异方法)

    很多初使用Vue的同学会发现,在改变数组的值的时候,值确实是改变了,但是视图却无动于衷,果然是因为数组太高冷了吗? 查看官方文档才发现,不是女神太高冷,而是你没用对方法. 看来想让女神自己动,关键得用 ...

  4. 浅谈js分页的几种方法

    一个项目中必然会遇到分页这种需求的,分页可以使数据加载更合理,也让页面显示更美观,更有层次感!那么js分页到底如何实现呢?下面我就来讲一下三种循序渐进的方法 1.自己纯手写分页 更深入的去理解分页的意 ...

  5. 浅谈C#泛型

    一.为什么要提出泛型的概念 我们在声明对象或者方法中,对象中成员变量的定义或者函数参数都传递都要指定具体的对象类型,但是有的时候参数的类型是变化的,但是实现的功能却又差不多,这个时候我们就想,是否存在 ...

  6. 浅谈Java泛型中的extends和super关键字(转)

    通配符 在本文的前面的部分里已经说过了泛型类型的子类型的不相关性.但有些时候,我们希望能够像使用普通类型那样使用泛型类型: 向上造型一个泛型对象的引用 向下造型一个泛型对象的引用 向上造型一个泛型对象 ...

  7. 浅谈Java泛型中的extends和super关键字

    泛型是在Java 1.5中被加入了,这里不讨论泛型的细节问题,这个在Thinking in Java第四版中讲的非常清楚,这里要讲的是super和extends关键字,以及在使用这两个关键字的时候为什 ...

  8. 转载--浅谈spring4泛型依赖注入

    转载自某SDN-4O4NotFound Spring 4.0版本中更新了很多新功能,其中比较重要的一个就是对带泛型的Bean进行依赖注入的支持.Spring4的这个改动使得代码可以利用泛型进行进一步的 ...

  9. 浅谈Java泛型之<? extends T>和<? super T>的区别

    关于Java泛型,这里我不想总结它是什么,这个百度一下一大堆解释,各种java的书籍中也有明确的定义,只要稍微看一下就能很快清楚.从泛型的英文名字Generic type也能看出,Generic普通. ...

随机推荐

  1. python [:-1] 与 [::-1]

    line = "abcde"line[:-1]结果为:'abcd' line = "abcde"line[::-1]结果为:'edcba' [:-1] b = ...

  2. vSphere虚拟机磁盘热扩容

    1.添加硬盘 2.刷新服务器文件系统 新添加的硬盘需要刷新文件系统,要不然不能识别新添加的硬盘. 对scsi_host进行重新扫描,查找 scsi 驱动器的号 驱动号为scsi后面的数字,即为2,此时 ...

  3. python插入记录后获取最后一条数据的id

    python插入记录后取得主键id的方法(cursor.lastrowid和conn.insert_id()) 参考:https://blog.csdn.net/qq_37788558/article ...

  4. 【spring-boot】spring-boot整合ehcache实现缓存机制

    EhCache 是一个纯Java的进程内缓存框架,具有快速.精干等特点,是Hibernate中默认的CacheProvider. ehcache提供了多种缓存策略,主要分为内存和磁盘两级,所以无需担心 ...

  5. python学习笔记(十七)网络编程之urllib模块

    如何用python打开一个网站或者请求一个接口呢,我们在这篇博客介绍一下. 首先我们得导入一个urllib模块,这个模块是python自带的标准模块,直接导入就能使用,但是用起来不方便,先看个简单的打 ...

  6. 细说PHP的FPM

    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++基础概念++ C ...

  7. Ubuntu解压命令全览

    1. Ubuntu解压命令全览.tar 解包:tar xvf FileName.tar 打包:tar cvf FileName.tar DirName 注:tar是打包,不是压缩! .gz 解压1:g ...

  8. Log4net 自定义字段 写入Oracle 使用ODP.NET Managed驱动

    一.环境说明: 开发工具:vs2010   ,数据库:oracle 11g ,版本:log4net的目前最新版本1.2.13.0    :  Oracle.ManagedDataAccess.dll ...

  9. iOS 绘制一个表盘时钟,秒针效果可以“扫秒/游走”

    最近自己 也尝试写了一个表盘时钟,初衷源于等车时候一个老奶奶问时间,我打开手机,时间数字对我来说相对敏感,但是老奶奶是看不清的,我想识别 还是看表盘 老远 看时针分针角度就可以识别当前时间. 于是我想 ...

  10. Web前端页面的浏览器兼容性测试心得(一)搭建测试用本地静态服务器

    自从实习以来,我体验了由一个人编程再到多人协作编程的转换.同时也接触了很多新鲜事物,学到了很多东西.工作时,常常需要多个人协同测试一张H5页面(PC.手机.平板等跨设备测试),也会经常把页面给PM或老 ...