摘要:本文介绍了如何定义一个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. ledecode Reverse Words in a String III

    557. Reverse Words in a String III Given a string, you need to reverse the order of characters in ea ...

  2. Design Patterns Example Code (in C++)

    Overview Design patterns are ways to reuse design solutions that other software developers have crea ...

  3. goland激活

    http://blog.csdn.net/benben_2015/article/details/78725467 http://blog.csdn.net/john_f_lau/article/de ...

  4. 008-mac下apache tomcat 测试授权

    一.下载 下载合适版本即可zip包 2.对bin下的*.sh授权 chmod 755 *.sh 3.80端口 https://blog.csdn.net/ilovesmj/article/detail ...

  5. js 屏蔽浏览器右键菜单

    <script type="text/javascript"> function doNothing(){ window.event.returnValue=false ...

  6. java 多线程 day07 多线程共享数据

    /** * Created by chengtao on 17/12/3. * 多个线程 如何共享数据? * 常见实例:多个窗口同时售卖火车票 */public class Thread0701_Mu ...

  7. nanomsg(ZeroMQ with C)

    1.应用手册 https://github.com/nanomsg/nanomsg % mkdir build % cd build % cmake .. % cmake --build . % ct ...

  8. SpringBoot的核心注解和配置

    一.入口类和SpringBootApplication Spring Boot的项目一般都会有*Application的入口类,入口类中会有main方法,这是一个标准的Java应用程序的入口方法. @ ...

  9. map::erase陷阱

    map::erase函数在不同版本stl中的差异 1. C++98和C++11标准 http://www.cplusplus.com/reference/map/map/erase/ 2. pj st ...

  10. centos7使用中文输入法

    centos7自带中文输入法,可能我们在安装时会跳过选择汉语拼音,我们来重新设置一下吧 假如你在命令行界面,输入Ctrl+Alt+F1进入图形界面 点击左上角系统工具   --> 设置 --&g ...