浅谈C#泛型的定义、继承、方法和约束
摘要:本文介绍了如何定义一个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#泛型的定义、继承、方法和约束的更多相关文章
- 【ASP.NET MVC系列】浅谈表单和HTML辅助方法
[01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作篇)(下) [04]浅谈ASP. ...
- 浅谈Java——泛型DAO
首先解释一下为什么要学习泛型DAO.平时在写DAO的时候是一个接口对应一个实现类,实现类里面要写很多的操作数据库的方法.当我们有很多的javaben的时候我们会写很多的接口和实现类,并且里面的代码都是 ...
- 浅谈Vue响应式(数组变异方法)
很多初使用Vue的同学会发现,在改变数组的值的时候,值确实是改变了,但是视图却无动于衷,果然是因为数组太高冷了吗? 查看官方文档才发现,不是女神太高冷,而是你没用对方法. 看来想让女神自己动,关键得用 ...
- 浅谈js分页的几种方法
一个项目中必然会遇到分页这种需求的,分页可以使数据加载更合理,也让页面显示更美观,更有层次感!那么js分页到底如何实现呢?下面我就来讲一下三种循序渐进的方法 1.自己纯手写分页 更深入的去理解分页的意 ...
- 浅谈C#泛型
一.为什么要提出泛型的概念 我们在声明对象或者方法中,对象中成员变量的定义或者函数参数都传递都要指定具体的对象类型,但是有的时候参数的类型是变化的,但是实现的功能却又差不多,这个时候我们就想,是否存在 ...
- 浅谈Java泛型中的extends和super关键字(转)
通配符 在本文的前面的部分里已经说过了泛型类型的子类型的不相关性.但有些时候,我们希望能够像使用普通类型那样使用泛型类型: 向上造型一个泛型对象的引用 向下造型一个泛型对象的引用 向上造型一个泛型对象 ...
- 浅谈Java泛型中的extends和super关键字
泛型是在Java 1.5中被加入了,这里不讨论泛型的细节问题,这个在Thinking in Java第四版中讲的非常清楚,这里要讲的是super和extends关键字,以及在使用这两个关键字的时候为什 ...
- 转载--浅谈spring4泛型依赖注入
转载自某SDN-4O4NotFound Spring 4.0版本中更新了很多新功能,其中比较重要的一个就是对带泛型的Bean进行依赖注入的支持.Spring4的这个改动使得代码可以利用泛型进行进一步的 ...
- 浅谈Java泛型之<? extends T>和<? super T>的区别
关于Java泛型,这里我不想总结它是什么,这个百度一下一大堆解释,各种java的书籍中也有明确的定义,只要稍微看一下就能很快清楚.从泛型的英文名字Generic type也能看出,Generic普通. ...
随机推荐
- Apache mahout 源码阅读笔记--协同过滤, PearsonCorrelationSimilarity
协同过滤源码路径: ~/project/javaproject/mahout-0.9/core/src $tree main/java/org/apache/mahout/cf/taste/ -L 2 ...
- nodejs实战《一起学 Node.js》 使用 Express + MongoDB 搭建多人博客
GitHub: https://github.com/nswbmw/N-blog N-blog 使用 Express + MongoDB 搭建多人博客 开发环境 Node.js: 6.9.1 Mong ...
- flatpickr功能强大的日期时间选择器插件
flatpickr日期时间选择器支持移动手机,提供多种内置的主题效果,并且提供对中文的支持.它的特点还有: 使用SVG作为界面的图标. 兼容jQuery. 支持对各种日期格式的解析. 轻量级,高性能, ...
- Jmeter添加变量的四种方法
一.在样本中添加同请求一起发送的参数.根据服务器设置的数据类型,来添加不同类型的参数 二.用户定义的变量 1.创建:添加->配置元件->用户定义的变量 2.作用:当前的线程组内所有Samp ...
- PAT 1110 Complete Binary Tree[比较]
1110 Complete Binary Tree (25 分) Given a tree, you are supposed to tell if it is a complete binary t ...
- genymotion——在虚拟机中当中安装genymotion,启动已经新增好的设备时,提示:the virtual device got no ip address
1.启动已经新增好的设备时,提示:the virtual device got no ip address,于是在网上搜索该问题,便得到提示,先启动virtual box中的该模拟设备,于是便启动,出 ...
- 禅道ZenTao在windows和Lniux下集成安装环境和一键安装方法整理
一共4种安装方法看官可以根据你自己的实际环境来选择一个都很简单 windows下用禅道官网的一键安装包方法(推荐): 为了简化大家在windows下面的安装,我们在xampp基础上做了禅道的windo ...
- Flask组件 flask_session
flask-session是flask框架的session组件,由于原来flask内置session使用签名cookie保存,该组件则将支持session保存到多个地方,如: redis memcac ...
- java实现FTP下载文件
ftp上传下载文件,是遵照ftp协议上传下载文件的,本例仅以下载文件为例. 重要的方法解释: 1.FTP功能相关依赖路径:org.apache.commons.net.ftp.*: 2.ftp默认端口 ...
- 28UDP
UDP通信流程步骤: 服务端: 等待(被动)接收发送 1: 创建 socket: socket() 2: 绑定端口: bind() 3: 读取消息: read() 4: 发送消息 ...