摘要:本文介绍了如何定义一个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. linux服务器自动切割日志

    需求 由于nginx的日志会不停地增大,所以需要我们自己去切割日志,方便管理,需要达到以下的效果: 按日期自动切割日志,最小单位是天. 当日志总量超过一定量时,自动直接清理日志,限定总量不能超过100 ...

  2. Python程序员的10个常见错误(转)

    add by zhj:虽然学Python也有两年了,但这些问题的确容易犯,看来对Python的理解还有些地方不深入.先转了,有时间再好好看 译文:http://blog.jobbole.com/682 ...

  3. git学习------>git-rev-parse命令初识

    一.准备工作 第一步:在d盘git test目录下,新建工作区根目录demo,进入该目录后,执行git init创建版本库. DH207891+OuyangPeng@DH207891 MINGW32 ...

  4. GROUP BY 和 ORDER BY一起使用

    转:http://lzfhope.blog.163.com/blog/static/636399220092554045196/ 环境:oracle 10g单单group by 或者order by本 ...

  5. 两台Linux系统之间传输文件

    用CRT分别连上两台需要传输文件的linux系统服务器,并检查防火墙是否关闭. 查看防火墙状态: /etc/init.d/iptables status 若防火墙启用,暂时关闭防火墙: /etc/in ...

  6. 在MFC里面实现线程的实例

    线程是一种从软件到硬件的技术,主要目的是为了提高运行速度,和多任务. ××××××××××××××××××××××××××××××××××××需要储备的资料(他人的)××××××××××××××××× ...

  7. 手把手教 GitHub + Hexo 搭建博客

    前言 在很久以前,博主就想着要有自主的博客专栏或者网站.经历了博客园这个需要所谓的编辑审核,一直比较困惑,这些编辑是什么出身,怎么知道技术博客的价值性. 接下来找到了开源中国,这个可以自由发言的地方. ...

  8. 实现:左边为菜单导航,当一个菜单中包含多个Tabs,并且不同的Tab要根据权限的不同显示。

    1.前台代码 //当点击左侧菜单时,将访问Controller中的Home方法,这样就会根据用户权限的不同,通过后台的判断来决定显示的页面<li class="@(ViewBag.Se ...

  9. php等守护进程监控脚本(转载 http://www.9958.pw/post/php_script_scan)

    此脚本用户守护监控进程的执行情况,因为有的时候,我们用各类开发语言做的守护进程可能会因为一些特殊情况被退出,所以此脚本就是为了重启这些进程 代码: #!/bin/bash EMAIL='9958_pw ...

  10. PKU 1321 棋盘问题(搜索+剪枝)

    #include<iostream> #include<cstring> using namespace std; ],ans; ][]; void dfs(int i) { ...