C#2.0泛型

泛型是什么

一种类型占位符,或称之为类型参数。我们知道在一个方法中,一个变量的值可以作为参数,但其实这个变量的类型本身也可以作为参数。泛型允许我们在调用的时候再指定这个类型参数是什么。在.net中,泛型能够给我们带来的两个明显好处是——类型安全和减少装箱、拆箱。

 

泛型最常见的用途是泛型集合,命名空间System.Collections.Generic 中包含了一些基于泛型的集合类,使用泛型集合类可以提供更高的类型安全性,还有更高的性能,避免了非泛型集合的重复的装箱和拆箱。

      很多非泛型集合类都有对应的泛型集合类,我觉得最好还是养成用泛型集合类的好习惯,他不但性能上好而且 功能上要比非泛型类更齐全。下面是常用的非泛型集合类以及对应的泛型集合类:

    

非泛型集合类泛型集合类
ArrayListList<T>
HashTableDIctionary<T>
QueueQueue<T>
StackStack<T>
SortedListSortedList<T>

最显著的一点就是它参数化了类型,把类型作为参数抽象出来,从而使我们在实际的运用当中能够更好的实现代码的重复利用,同时它提供了更强的类型安全,更高的效率,不过在约束方面,它只支持显示的约束,这样在灵活性方面就显得不是那么好了.我觉得它之所以能够提供更高的效率是因为泛型在实例化的时候采用了"on-demand"的模式,即按需实例化,发生在JIT(Just In Time)编译时.
      下面来看如何定义一个泛型类,很简单,你只需要意识到一点,在这里,类型已经被参数化了:

using System;
using System.Collections.Generic;
using System.Text;

namespace GenericTest
ExpandedBlockStart.gifContractedBlock.gif
{
    
class Program
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
static void Main(string[] args)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//使用string,int来实例化Test<T,S>类
            Test<stringint> t = new Test<stringint>("SHY520",22);

            
//调用泛型类中的方法
            t.SetValue();
        }

    }


ExpandedSubBlockStart.gifContractedSubBlock.gif    
/// <summary>
    
/// 定义一个泛型类,该类有两个类型参数,分别是T,S
    
/// http://pw.cnblogs.com
    
/// </summary>
    
/// <typeparam name="T">类型参数</typeparam>
    
/// <typeparam name="S">类型参数</typeparam>

    public class Test<T,S>
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
//泛型类的类型参数可用于类成员
        private T name;
        
private S age;

        
public Test(T Name,S Age)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
this.name = Name;
            
this.age = Age;
        }


        
public void SetValue()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            Console.WriteLine(name.ToString());
            Console.WriteLine(age.ToString());
        }

    }

}


        上面的例子不是很恰当,目的是让初学泛型的你了解一下泛型的定义及实例化方法,如上,我们定义了一个泛型类,那么如何实现泛型类的继承呢?这里需要满足下面两点中的任何一点即可:
1、泛型类继承中,父类的类型参数已被实例化,这种情况下子类不一定必须是泛型类;
2、父类的类型参数没有被实例化,但来源于子类,也就是说父类和子类都是泛型类,并且二者有相同的类型参数;

    //如果这样写的话,显然会报找不到类型T,S的错误
ExpandedBlockStart.gifContractedBlock.gif
    public class TestChild : Test<T, S> { }

    
//正确的写法应该是
ExpandedBlockStart.gifContractedBlock.gif
    public class TestChild : Test<stringint>{ }

ExpandedBlockStart.gifContractedBlock.gif    
public class TestChild<T, S> : Test<T, S> { }

ExpandedBlockStart.gifContractedBlock.gif    
public class TestChild<T, S> : Test<String, int> { }

接着我们来看看泛型接口,其创建以及继承规则和上面说的泛型类是一样的,看下面的代码:
    public interface IList<T> 
ExpandedBlockStart.gifContractedBlock.gif    
{
        T[] GetElements();
    }
 
    
public interface IDictionary<K,V>             
ExpandedBlockStart.gifContractedBlock.gif    
{
        
void Add(K key, V value); 
    }
 

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

        }

    }


在来看一下泛型委托,首先我们定义一个类型参数为T的委托,然后在类中利用委托调用方法:
using System;
using System.Collections.Generic;
using System.Text;

namespace GenericTest
ExpandedBlockStart.gifContractedBlock.gif
{
    
//定义一个委托,类型参数为T,返回值类型T
    
//泛型委托支持在返回值和参数上应用类型参数
    delegate string GenericDelete<T>(T value);

    
class test
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
static string F(int i) return "SHY520"; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
static string G(string s) return "SHY520"; }

        
static void Main(string[] args)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            GenericDelete
<string> G1 = G;
            GenericDelete
<int> G2 = new GenericDelete<int>(F);
        }

    }
 
}


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

using System;
using System.Collections.Generic;
using System.Text;

namespace GenericTest
ExpandedBlockStart.gifContractedBlock.gif
{
    
class GenericClass
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
//申明一个泛型方法
        public T getvalue<T>(T t)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
return t;
        }


        
//调用泛型方法
        
//注意:在调用泛型方法时,对泛型方法的类型参数实例化
        public int useMethod()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
return this.getvalue<int>(10);
        }


        
//重载getvalue方法
        public int getvalue(int i)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
return i;
        }

    }


    
//下面演示覆盖
    
//要注意的是,泛型方法被覆盖时,约束被默认继承,不需要重新指定约束关系
    abstract class Parent
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
public abstract K TEST<K, V>(K k, V v) where K : V;

    }


    
class Child : Parent
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
public override T TEST<T, S>(T t, S s)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
return t;
        }

    }

}


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

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

2、接口约束
ExpandedBlockStart.gifContractedBlock.gif    interface IPrintable void Print(); 
    }

ExpandedBlockStart.gifContractedBlock.gif    
interface IComparable<T> int CompareTo(T v);}
ExpandedBlockStart.gifContractedBlock.gif    
interface IKeyProvider<T> { T GetKey(); }
    
class Dictionary<K,V> 
    where K: IComparable
<K> 
    where V: IPrintable, IKeyProvider
<K> 
ExpandedBlockStart.gifContractedBlock.gif    

    
// 可以在类型为K的变量上调用CompareTo, 
    
// 可以在类型为V的变量上调用Print和GetKey 
    }

3、构造器约束
ExpandedBlockStart.gifContractedBlock.gifclass A public A() { } } 
ExpandedBlockStart.gifContractedBlock.gif
class B public B(int i) { } } 
class C<T> 
where T : 
new() 
ExpandedBlockStart.gifContractedBlock.gif

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

4、值/引用类型约束
ExpandedBlockStart.gifContractedBlock.gifpublic struct A {  } 
ExpandedBlockStart.gifContractedBlock.gif
public class B {  } 
class C<T> 
where T : 
struct 
ExpandedBlockStart.gifContractedBlock.gif

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

转载于:https://www.cnblogs.com/guodapeng/archive/2009/05/30/1492383.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/406913.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

css行高line-height的一些深入理解及应用

1. 一些字面意思 “行高”是指两行文字间基线之间的距离。基线是在英文字母中用到的一个概念&#xff0c;我们刚学英语的时使用的那个英语本子每行有四条线&#xff0c;其中底部第二条线就是基线&#xff0c;是a,c,z,x等字母的底边线。下图的红色线即为基线 2. line-height与l…

echarts使用大总结

echarts图表x轴数据太多显示不全的问题 问题如图&#xff0c;x轴数据条数过多可能导致x轴显示不全&#xff0c;开始我使用下面方法 xAxis: {type: "category",min: min,max: max,data:time,axisLabel: {interval:num,//interval为x轴两相邻数据之间所包含数据条数&a…

我对CSS vertical-align的一些理解与认识(一)

1. vertical-align一大堆乱七八糟的属性 有句俗语叫做“见多不怪”&#xff0c;我估摸着这些top,bottom属性大家都见过&#xff0c;没啥看头&#xff0c;没啥说头。老实讲&#xff0c;我看到这些养臭虫的属性也头疼&#xff0c;所以&#xff0c;忘了他们&#xff0c;我们说点有…

我对CSS vertical-align的一些理解与认识(二)

1. 我对不同浏览器解析vertical-align属性的理解 在上集中&#xff0c;在最后提供的实例中&#xff0c;vertical-align:middle实际上应该是与后面的文字是独立的&#xff0c;毫无关联&#xff0c;就是说vertical-align无论是什么&#xff0c;都不影响文字在box中的位置&#x…

VC2010如何给ActiveX添加事件

利用VC开发ActiveX时&#xff0c;需要给控件添加标准事件或自定义事件&#xff0c;在VC6中有多种方法&#xff1a; 一、按Ctrl W 打开类向导&#xff0d;&#xff1e;切换到“ActiveX Events"&#xff0d;&#xff1e;Add Event...&#xff0c;如图&#xff1a; 二、右…

CSS中height:100%和height:inherit的异同

1. height:100%和height:inherit的异同 1.1 兼容性差异 height:100% IE6 √ height:inherit IE8 √ 1.2 大多数情况作用是一样的 除去兼容性&#xff0c;大多数情况下&#xff0c;两者作用是一样的&#xff0c;甚至都很难想出不一样的理由 父容器height: auto&#xff0c…

cxxtest单元测试框架源码分析(二):所有对外功能实现分析

CxxTest的大部分诊断功能都是通过宏定义实现的&#xff0c;而且这部分的定义以及所有测试套的基类CxxTest:TestSuite定义和实现都在TestSuite.h和TestSuite.cpp里面。下面我们将通过分析这两个文件来分析CxxTest的对外功能体现。 1 //所有的类以及定义都是在CxxTest名称空间中2…

absolute元素在text-align属性下的对齐显示

1. absolute元素是否可以响应text-align属性&#xff1f; 众所周知&#xff0c;text-align属性可以有效作用于inline/inline-block水平的元素&#xff0c;那么应用了position:absloute/fixed声明的元素呢&#xff1f; 上面效果中的图片就是应用了position: absolute声明&#…

vue-cli proxy中跨域中pathRewrite配置理解

1. vue本地项目调试线上接口出现跨域问题 2. 通过在 config/index.js 配置文件中找到proxyTable配置项 dev: {// PathsassetsSubDirectory: static,assetsPublicPath: /,proxyTable: {/api: {target: http://XX.XX.XX.XX:8083,changeOrigin: true,pathRewrite: {^/api: /api …

CSS3选择器:nth-child和:nth-of-type之间的差异

1. 深呼吸&#xff0c;直接内容 :nth-child和:nth-of-type都是CSS3中的伪类选择器&#xff0c;其作用近似却又不完全一样&#xff0c;对于不熟悉的人对其可能不是很区分&#xff0c;本文就将介绍两者的不同&#xff0c;以便于大家正确灵活使用这两类选择器 先看一个简单的实例…

CSS3中的display:grid网格布局介绍

1.网格布局(grid): 它将网页划分成一个个网格&#xff0c;可以任意组合不同的网格&#xff0c;做出各种各样的布局; 2.基本概念&#xff1a; 容器和项目&#xff0c;如图所示&#xff1a; <div class"content"><div class"b">1</div>&…

微信小程序知识点GET

1. app.json中的pages用来设置小程序包含哪些页面以及页面的路径、window用来设置默认页面的窗口表现形式、tabBar用来设置小程序底部tab的表现 2. app.js中的App()函数用来注册一个小程序&#xff0c;接受的对象参数用来指定小程序的生命周期函数等&#xff0c;注意App()必须…

CSS3 - 新单位vw、vh、vmin、vmax使用详解(附样例)

关于height:100%和height:100vh的区别 像 px、em 这样的长度单位大家肯定都很熟悉&#xff0c;前者为绝对单位&#xff0c;后者为相对单位。CSS3 又引入了新单位&#xff1a;vw、vh、vmin、vmax。下面对它们做个详细介绍。 一、基本说明 1&#xff0c;vw、vh、vmin、vmax 的…

Enze Second day

哈喽&#xff0c;很高兴在云和学院又学了一天的新知识&#xff0c;现在&#xff0c;我来继续总结一下今天所学的以及对昨天的一些补充。 变量 • 声明变量的语法格式:–数据类型 变量名;•赋值: 变量名值;变量的命名 •命名规则&#xff1a;–1 必须以“字母”_或符号开头…