澳门新萄京官方网站-www.8455.com-澳门新萄京赌场网址

澳门新萄京官方网站:什么是泛型,泛型总结

2019-08-10 作者:www.8455.com   |   浏览(156)

一、List

 

 

怎么着是泛型

       大家在编写程序时,平时遇到五个模块的机能拾贰分相似,只是一个是拍卖int数据,另三个是处理string数据,大概另外自定义的数据类型,但大家从未章程,只好分别写多少个艺术管理每种数据类型,因为方法的参数类型分歧。有未有一种方法,在情势中传唱通用的数据类型,那样不就能够统一代码了吧?泛型的产出正是特地解决这一个难题的。读完本篇作品,你会对泛型有越来越深的询问。

怎么要动用泛型
为了明白这一个难题,大家先看上面包车型大巴代码,代码省略了有些剧情,但作用是兑现一个栈,这么些栈只可以管理int数据类型:

public class Stack

    {

        private int[] m_item;

        public int Pop(){...}

        public void Push(int item){...}

        public Stack(int i)

        {

            this.m_item = new int[i];

        }

}

上边代码运营的很好,可是,当大家需求叁个栈来保存string类型时,该怎么做呢?相当多人都会想到把地点的代码复制一份,把int改成string不就行了。当然,那样做我是尚未别的难点的,但二个可观的先后是不会这么做的,因为她想到若从此再须要long、Node类型的栈该如何做吗?还要再复制吗?优异的程序猿会想到用二个通用的数据类型object来贯彻这些栈:

public class Stack

    {

        private object[] m_item;

        public object Pop(){...}

        public void Push(object item){...}

        public Stack(int i)

        {

            this.m_item = new[i];

        }

      

    }

以此栈写的不利,他特别灵活,可以接到任何数据类型,能够说是一劳永逸。但周详地讲,亦不是未有破绽的,主要表以往:

当Stack管理值类型时,会并发装箱、折箱操作,那将要托管堆上分配和回收多量的变量,若数据量大,则质量损失十分严重。 
在管理援用类型时,纵然未有装箱和折箱操作,但将用到数据类型的强制转变操作,扩张管理器的担当。 
在数据类型的强制转变上还也有更要紧的标题(若是stack是Stack的二个实例):
Node1 x = new Node1();

            stack.Push(x);

         Node2 y = (Node2)stack.Pop();

地点的代码在编写翻译时是全然没难题的,但由于Push了二个Node1类型的数量,但在Pop时却要求改动为Node2类型,那将出现程序运维时的类型转变十分,但却逃离了编写翻译器的检查。

 

针对object类型栈的难点,大家引进泛型,他得以优雅地化解这个标题。泛型用用三个通过的数据类型T来取代object,在类实例化时钦命T的项目,运维时(Runtime)自动编写翻译为地点代码,运转效能和代码品质都有异常的大拉长,况且保障数据类型安全。

 

动用泛型
下边是用泛型来重写上边的栈,用一个通用的多寡类型T来作为一个占位符,等待在实例化时用叁个实际上的花色来顶替。让大家来拜望泛型的威力:

public class Stack<T>

    {

        private T[] m_item;

        public T Pop(){...}

        public void Push(T item){...}

        public Stack(int i)

        {

            this.m_item = new T[i];

        }

}

类的写法不改变,只是引进了通用数据类型T就足以适用于别的数据类型,何况类型安全的。那么些类的调用方法:

//实例化只可以保留int类型的类

Stack<int> a = new Stack<int>(100);

      a.Push(10);

      a.Push("8888"); //这一行编写翻译不通过,因为类a只抽取int类型的数据

      int x = a.Pop();

 

//实例化只可以保留string类型的类

Stack<string> b = new Stack<string>(100);

b.Push(10);    //这一行编译不经过,因为类b只接受string类型的数据

      b.Push("8888");

string y = b.Pop();

 

以此类和object实现的类有一同差异的界别:

1.       他是体系安全的。实例化了int类型的栈,就不能够管理string类型的数据,别的数据类型也同样。

2.       没有需求装箱和折箱。这么些类在实例化时,依照所传颂的数据类型生开支地代码,本地代码数据类型已规定,所以不用装箱和折箱。

3.       无需类型调换。

 

泛型类实例化的驳斥
C#泛型类在编写翻译时,先生成人中学等代码IL,通用类型T只是一个占位符。在实例化类时,依照用户钦赐的数据类型代替T并由即时编写翻译器(JIT)生开销地代码,那一个地面代码中一度接纳了事实上的数据类型,等同于用实际类型写的类,所以差异的密闭类的地面代码是区别等的。根据这一个原理,大家得以那样以为:

泛型类的不如的密封类是各自不一样的数据类型。

例:Stack<int>和Stack<string>是多个精光未有别的涉及的类,你能够把她看成类A和类B,这些解释对泛型类的静态成员的明白有非常的大帮扶。

 

泛型类中数据类型的羁绊
工程师在编写泛型类时,总是会对通用数据类型T实行有意或下意识地有假想,约等于说这么些T一般的话是无法适应全数品种,但怎么样界定调用者传入的数据类型呢?那就须求对传播的数据类型实行封锁,约束的诀假设钦命T的祖宗,即一连的接口或类。因为C#的单根承接性,所以约束能够有两个接口,但最多只可以有二个类,况且类必须在接口以前。那时就用到了C#2.0的新扩充关键字:

public class Node<T, V> where T : Stack, IComparable

        where V: Stack

    {...}

以上的泛型类的束缚注明,T必须是从Stack和IComparable承接,V必须是Stack或从Stack承继,不然将不只怕透过编写翻译器的品种检查,编写翻译战败。

通用类型T未有特指,但因为C#中保有的类都以从object承接来,所以他在类Node的编辑撰写中只可以调用object类的不二诀要,那给程序的编写变成了不便。比如你的类设计只须求帮助二种数据类型int和string,何况在类中须求对T类型的变量非常的大小,但那个却不恐怕完成,因为object是尚未十分的大小的点子的。 了消除这一个难点,只需对T实行IComparable约束,那时在类Node里就足以对T的实例试行CompareTo方法了。这几个标题能够扩展到其余用户自定义的数据类型。

一旦在类Node里需求对T重新张开实例化该如何是好吧?因为类Node中不知情类T到底有啥样构造函数。为了消除这几个标题,须要利用new约束:

public class Node<T, V> where T : Stack, new()

        where V: IComparable

内需留心的是,new约束只好是无参数的,所以也须要相应的类Stack必须有三个无参构造函数,不然编写翻译失利。

C#中数据类型有两大类:引用类型和值类型。引用类型如享有的类,值类型一般是语言的最基本类型,如int, long, struct等,在泛型的牢笼中,大家也得以大面积地范围类型T必须是援用类型或必须是值类型,分别对应的基本点字是class和struct:

public class Node<T, V> where T : class

        where V: struct

 

泛型方法
泛型不只能作用在类上,也可独自用在类的章程上,他可依靠章程参数的项目自动适应种种参数,那样的措施叫泛型方法。看下边包车型地铁类:

public class Stack2

    {

        public void Push<T>(Stack<T> s, params T[] p)

        {

            foreach (T t in p)

            {

                s.Push(t);

            }

        }

}

原先的类Stack贰遍只可以Push贰个数码,这几个类Stack2扩大了Stack的效果(当然也可以向来写在Stack中),他能够贰回把几个数据压入Stack中。当中Push是一个泛型方法,这么些主意的调用示举例下:

Stack<int> x = new Stack<int>(100);

    Stack2 x2 = new Stack2();

    x2.Push(x, 1, 2, 3, 4, 6);

    string s = "";

    for (int i = 0; i < 5; i )

    {

        s = x.Pop().ToString();

    }    //至此,s的值为64321

   

 

泛型中的静态成员变量
在C#1.x中,大家知道类的静态成员变量在不一样的类实例间是分享的,况且他是通过类名访问的。C#2.0中出于引入了泛型,导致静态成员变量的体制出现了有的转移:静态成员变量在一样密封类间分享,区别的查封类间不分享。

这也特别轻易通晓,因为区别的密闭类纵然有同等的类名称,但鉴于各自传入了不一致的数据类型,他们是完全差异的类,举例:

Stack<int> a = new Stack<int>();

Stack<int> b = new Stack<int>();

Stack<long> c = new Stack<long>();

类实例a和b是同样类型,他们之间分享静态成员变量,但类实例c却是和a、b完全分裂的项目,所以无法和a、b分享静态成员变量。

泛型中的静态构造函数
静态构造函数的条条框框:只好有四个,且不能够有参数,他只好被.NET运转时自动调用,而不可能人工资调节用。

泛型中的静态构造函数的原理和非泛型类是同一的,只需把泛型中的差别的密闭类驾驭为分裂的类就能够。以下三种景况可激发静态的构造函数:

1.       特定的密闭类第二回被实例化。

2.       特定密封类中任一静态成员变量被调用。

 

泛型类中的方法重载
格局的重载在.Net Framework中被大量行使,他需求重载具备分歧的签名。在泛型类中,由于通用类型T在类编排时并不鲜明,所以在重载时有一些注意事项,那些事项大家经过以下的例子表明:

public class Node<T, V>

    {

        public T add(T a, V b)          //第一个add

        {

            return a;

        }

        public T add(V a, T b)          //第二个add

        {

            return b;

澳门新萄京官方网站:什么是泛型,泛型总结。        }

        public int add(int a, int b)    //第三个add

        {

            return a b;

        }

}

地方的类很分明,假若T和V都传入int的话,多个add方法将富有一样的签订契约,但以此类还是能经过编写翻译,是或不是会唤起调用混淆将要这几个类实例化和调用add方法时判别。请看上面调用代码:

Node<int, int> node = new Node<int, int>();

    object x = node.add(2, 11);

这些Node的实例化引起了四个add具有同样的签订契约,但却能调用成功,因为她开始时期相称了第多个add。但如若剔除了第八个add,上边的调用代码则不可能编写翻译通过,提醒方法产生的歪曲,因为运行时不可能在首先个add和第二个add之间采纳。

Node<string, int> node = new Node<string, int>();

        object x = node.add(2, "11");

   这两行调用代码可科学编写翻译,因为传播的string和int,使多少个add具备分裂的具名,当然能找到独一匹配的add方法。

由以上示例可见,C#的泛型是在实例的不二等秘书籍被调用时检查重载是或不是产生模糊,并非在泛型类本身编写翻译时检查。同时还搜查缉获一个关键尺度:

当一般方法与泛型方法具备同样的签署时,会覆盖泛型方法。

 

泛型类的措施重写
办法重写(override)的要紧难题是艺术签字的鉴定分别准则,在这点上她与方法重载同样,请仿效泛型类的办法重载。

 

泛型的使用限制
正文首就算在类中描述泛型,实际上,泛型还是能够用在类措施、接口、结构(struct)、委托等地点运用,使用方法大概同样,就不再呈报。

小结
C# 泛型是付出工具库中的七个珍贵和稀有之宝。它们得以拉长品质、类型安全和品质,减弱重复性的编制程序任务,简化总体编制程序模型,而这一切都是通过优雅的、可读性强的语法完结的。纵然C# 泛型的底子是 C 模板,但 C# 通过提供编译时安全和帮忙将泛型提升到了三个新水平。C# 利用了两等第编写翻译、元数据以及诸如约束和一般方法之类的创新性的定义。千真万确,C# 的昨日版本将承袭升高泛型,以便加多新的作用,并且将泛型扩大到诸如数码访谈或本地化之类的其他.NET Framework 领域。

 

 

 

封锁是指对泛型类型参数施加限制,用于限制能够传递到该品种参数的档案的次序系列。假如选取有个别约束不允许的类别来实例化,则会生出编写翻译时不当。约束使用where关键字钦命。

约束有4种类型:

1.基类约束

内定编写翻译器泛型类型参数必须派生自特定基类

修饰符 class 类名<类型参数列表> where 类型参数:基类名

{ 类体}

澳门新萄京官方网站:什么是泛型,泛型总结。2.接口约束

点名编译器泛型类型参数必须派生自特定接口

修饰符 class 类名<类型参数列表> where 类型参数:接口名

{ 类体}

3.暗中同意构造函数约束

指令编译器泛型类型参数公开了私下认可的公共构造函数(不带任何参数的集体构造函数)

修饰符 class 类名<类型参数列表> where 类型参数:new ()

{ 类体}

4.引用/值类型约束

指令编写翻译器泛型类型参数必须是引用类型或值类型

修饰符 class 类名<类型参数列表> where 类型参数:struct(或class)

{ 类体}

能够对一样等级次序参数使用三个约束,况兼封锁自个儿能够也足以是泛型类型,八个约束之间用逗号隔开分离。

 

泛型方法

1)、表示可透过索引访谈的靶子的强类型列表;提供用于对列表举行找寻、排序和操作的方法。
2)、是ArrayList类的泛型等效类。
3)、能够应用二个莫西干发型索引访谈此集聚中的成分;索引从零 发轫。
4)、能够接收null空援引(VB中的Nothing)。
5)、允许再一次成分

       大家在编写程序时,平时遭逢七个模块的机能十一分相像,只是八个是拍卖int数据,另二个是管理string数据,大概其余自定义的数据类型,但我们从未议程,只好分别写七个章程管理各样数据类型,因为方法的参数类型分化。有没有一种方法,在措施中流传通用的数据类型,那样不就足以统一代码了吧?泛型的面世就是特地化解那个主题素材的。读完本篇小说,你会对泛型有越来越深的询问。

    在C#2.0中,方法能够定义特定于其实施范围的泛型参数,如下所示:

二、List

缘何要使用泛型
为了了然那个主题材料,大家先看上面包车型地铁代码,代码省略了有的内容,但效果是落到实处三个栈,那一个栈只可以管理int数据类型:

澳门新萄京官方网站 1

List

public class Stack

    public class MyClass<T>
    {
        //内定MyMethod方法用以实行项目为X的参数
        public void MyMethod<X>(X x) 
        {
            //澳门新萄京官方网站 2
        }

List

    {

        //此方法也可不钦赐方法参数
        public void MyMethod<X>() 
        {
            //澳门新萄京官方网站 3
        }
    }   

List

        private int[] m_item;

澳门新萄京官方网站 4

三、List

        public int Pop(){...}

    固然带有类不适用泛型参数,你也足以定义方法特定的泛型参数,如下所示:

Capacity
获得或安装该内部数据结构在不调节大小的情状下能够容纳的要素总量。

        public void Push(int item){...}

澳门新萄京官方网站 5

Count
获取 List

        public Stack(int i)

    public class MyClass
    {
        //内定MyMethod方法用以实践项目为X的参数
        public void MyMethod<X>(X x) 
        {
            //澳门新萄京官方网站 6
        }

四、List

        {

        //此方法也认同钦赐方法参数
        public void MyMethod<X>() 
        {
            //澳门新萄京官方网站 7
        }
    }

Add
将指标增多到 List

            this.m_item = new int[i];

澳门新萄京官方网站 8

AddRange
将内定会集的成分加多到 List

        }

    注意:属性和索引器不可能内定本身的泛型参数,它们只好选取所属类中定义的泛型参数进行操作。

AsReadOnly
再次回到当前集中的只读 IList

}

    在调用泛型方法的时候,你能够提供要在调用场合选择的项目,如下所示:

BinarySearch(T)
选取默许的比较器在漫天已排序的 List

上边代码运维的很好,可是,当大家需求一个栈来保存string类型时,该如何是好呢?很六个人都会想到把上面包车型大巴代码复制一份,把int改成string不就行了。当然,那样做作者是未有任何问题的,但二个了不起的顺序是不会那样做的,因为她想到若从此再须要long、Node类型的栈该怎么着做啊?还要再复制吗?非凡的程序员会想到用三个通用的数据类型object来促成这几个栈:

//调用泛型方法
MyClass myClass = new MyClass();
myClass.MyMethod<int>(3);

BinarySearch(T, IComparer

public class Stack

    泛型推理:在调用泛型方法时,C#编写翻译器丰裕聪明,基于传入的参数类型来测算出科学的体系,何况它同意完全省略类型标准,如下所示:

BinarySearch(Int32, Int32, T, IComparer

    {

//泛型推理机制调用泛型方法
MyClass myClass = new MyClass();
myClass.MyMethod(3);

Clear
从 List

        private object[] m_item;

    注意:泛型方法无法只依据再次来到值的品种估量出类型,代码如下:

Contains
明确某成分是还是不是在 List

        public object Pop(){...}

澳门新萄京官方网站 9

ConvertAll

        public void Push(object item){...}

     public GenericMethodDemo()
     {        
        MyClass myClass = new MyClass();
        /****************************************************
        不恐怕从用法中国对外演出公司绎出方法“GenericMethod德姆o.MyClass.MyMethod<T>()”的门类参数。
        请尝试显式钦命项目参数。
        ***************************************************/
        int number = myClass.MyMethod();
     }

CopyTo(T[])
将整个 List

        public Stack(int i)

    public class MyClass
    {
        public T MyMethod<T>() 
        {
            //澳门新萄京官方网站 10
        }
    }

Exists
确定 List

        {

澳门新萄京官方网站 11

Find
检索与钦定谓词所定义的尺度相相称的成分,并回到整个 List

            this.m_item = new[i];

    泛型方法中泛型参数的自律,如下:

FindIndex(Predicate

        }

澳门新萄京官方网站 12

ForEach
对 List

      

    public class MyClass
    {
        
        public void MyMethod<X>(X x) where X:IComparable<X>
        {
            //澳门新萄京官方网站 13
        }
    }

GetEnumerator
重返循环访谈 List

    }

澳门新萄京官方网站 14

IndexOf(T)
招来钦点的对象,并重返整个 List

以此栈写的精确,他特别灵活,能够吸取任何数据类型,能够说是一劳永逸。但周全地讲,亦非未曾破绽的,首要表今后:

    您不可能为类等级的泛型参数提供格局品级的羁绊。类等级泛型参数的具备约束都无法不在类效用范围中定义,代码如下所示

Insert
将成分插入 List

当Stack处理值类型时,会现出装箱、折箱操作,那将要托管堆上分配和回收多量的变量,若数据量大,则品质损失十一分严重。 
在拍卖援用类型时,即使尚未装箱和折箱操作,但将用到数据类型的胁迫调换操作,扩张管理器的担当。 
在数据类型的劫持转换上还会有更要紧的标题(借使stack是Stack的贰个实例):
Node1 x = new Node1();

澳门新萄京官方网站 15

InsertRange
将聚合中的某个成分插入 List

            stack.Push(x);

    public class MyClass<T>
    {
        
        public void MyMethod<X>(X x,T t) where X:IComparable<X> where T:IComparer<T>
        {
            //澳门新萄京官方网站 16
        }
    }

LastIndexOf(T)
寻觅钦点的对象,并重临整个 List

         Node2 y = (Node2)stack.Pop();

澳门新萄京官方网站 17

Remove
从 List

地点的代码在编译时是一丝一毫没难题的,但出于Push了四个Node1类型的数额,但在Pop时却供给转换为Node2类型,那将面世程序运维时的类型转换格外,但却逃离了编写翻译器的自己商议。

而下边的代码是科学的

Reverse()
将整个 List

 

澳门新萄京官方网站 18

Sort()
运用私下认可比较器对全部 List

针对object类型栈的主题材料,大家引进泛型,他得以优雅地消除那些标题。泛型用用三个透过的数据类型T来代替object,在类实例化时钦命T的品类,运转时(Runtime)自动编写翻译为地面代码,运维成效和代码品质都有比较大抓好,並且保障数据类型安全。

    public class MyClass<T> where T:IComparable<T>
    {
        
        public void MyMethod<X>(X x,T t) where X:IComparable<X> 
        {
            //澳门新萄京官方网站 19
        }
    }

五、常用方法实例

 

澳门新萄京官方网站 20

(1)创设及起初化:
List

运用泛型
上边是用泛型来重写上边的栈,用一个通用的数码类型T来作为贰个占位符,等待在实例化时用二个实际的等级次序来顶替。让大家来探视泛型的威力:

    泛型参数虚方法的重写:子类方法必须再次定义该格局特定的泛型参数,代码如下

(2)加多二个要素 List.Add(T item)
mlist.Add("d");

public class Stack<T>

澳门新萄京官方网站 21

(3)加多集结成分
string[] Arr2
={"f","g"."h"};mlist.AddRange(Arr2);

    {

    public class MyBaseClass
    {
        public virtual void SomeMethod<T>(T t)
        {
            //澳门新萄京官方网站 22
        }
    }
    public class MyClass :MyBaseClass
    {
        public override void SomeMethod<X>(X x)
        {
            
        }
    }

(4)在index地方增加二个成分 Insert(int index,T item)
mlist.Insert(1,"p");

        private T[] m_item;

澳门新萄京官方网站 23

(5)遍历List中元素
foreach(T element in mlist)
T的项目与mlist证明时同样{  Console.WriteLine(element);}

        public T Pop(){...}

与此同期子类中的泛型方法无法再一次基类泛型方法的牢笼,这点和泛型类中的虚方法重写是有分别的,代码如下

(6)删除成分
List.Remove(T item)
除去一个值mlist.Remove("a");

        public void Push(T item){...}

澳门新萄京官方网站 24

List.RemoveAt(int
index);删除下标为index的因素mlist.RemoveAt(0);List.RemoveRange(int index,int
count); 下标index开始,删除count个元素mlist.RemoveRange(3,2);

        public Stack(int i)

    public class MyBaseClass
    {
        public virtual void SomeMethod<T>(T t) where T:new()
        {
            //澳门新萄京官方网站 25
        }
    }
    public class MyClass :MyBaseClass
    {
        //正确写法
        public override void SomeMethod<X>(X x)
        {
            
        }


        {

        ////错误 重写和显式接口实现情势的约束是从基方法承继的,由此不能够向来钦命那么些约束
        //public override void SomeMethod<X>(X x) where X:new()
        //{

大家在编写程序时,日常遇上多个模块的功用万分相像,只是三个是拍卖int数据,另贰个是拍卖string数据,或然其余自定义的数据类型,但我们没法,只可以分别写多少个方法管理各类数据类型,因为方法的参数类型分歧。有未有一种艺术,在章程中传出通用的数据类型,这样不就足以统一代码了吗?泛型的产出正是特意化解这几个难点的。读完本篇小说,你会对泛型有更加深的打听。
何以要动用泛型
为了打探那几个标题,大家先看下边包车型地铁代码,代码省略了一部分内容,但效果与利益是促成一个栈,这一个栈只好处理int数据类型:

            this.m_item = new T[i];

        //}
    }

public class Stack

        }

澳门新萄京官方网站 26

{

    private int[] m_item;

    public int Pop(){...}

    public void Push(int item){...}

    public Stack(int i)

    {

        this.m_item = new int[i];

    }

}

    子类方法调用虚拟方法的基类达成:它必须内定要代表泛型基础艺术类型所利用的门类实参。你能够团结显式的钦命它,也足以凭仗类型推理(假若也许的话)代码如下:

}

类的写法不变,只是引进了通用数据类型T就能够适用于任何数据类型,而且类型安全的。那些类的调用方法:

澳门新萄京官方网站 27

上边代码运营的很好,然则,当大家必要一个栈来保存string类型时,该咋办呢?比比较多个人都会想到把地点的代码复制一份,把int改成string不就行了。当然,那样做自己是未有任何难点的,但一个理想的主次是不会那样做的,因为她想到若从此再须求long、Node类型的栈该怎么着做啊?还要再复制吗?优良的程序员会想到用叁个通用的数据类型object来促成那么些栈:

//实例化只可以保留int类型的类

    public class MyBaseClass
    {
        public virtual void SomeMethod<T>(T t) where T:new()
        {
            //澳门新萄京官方网站 28
        }
    }
    public class MyClass :MyBaseClass
    {
        //正确写法
        public override void SomeMethod<X>(X x)
        {
            base.SomeMethod<X>(x);
            base.SomeMethod(x);
        }
    }

public class Stack

Stack<int> a = new Stack<int>(100);

澳门新萄京官方网站 29

{

    private object[] m_item;

    public object Pop(){...}

    public void Push(object item){...}

    public Stack(int i)

    {

        this.m_item = new[i];

    }



}

      a.Push(10);

泛型委托

本条栈写的精确,他特别灵活,能够采用任何数据类型,能够说是一劳永逸。但完美地讲,亦非未曾破绽的,首要呈今后:

      a.Push("8888"); //这一行编写翻译不通过,因为类a只抽取int类型的数目

    在某些类中定义的信托能够利用该类的泛型参数,代码如下

当Stack处理值类型时,会现出装箱、折箱操作,那将要托管堆上分配和回收大批量的变量,若数据量大,则品质损失十三分严重。
在拍卖援用类型时,纵然未有装箱和折箱操作,但将用到数据类型的勒迫转变操作,扩充管理器的担负。
在数据类型的威迫调换上还大概有更要紧的标题(假诺stack是Stack的八个实例):
Node1 x = new Node1();

      int x = a.Pop();

澳门新萄京官方网站 30

        stack.Push(x);

     Node2 y = (Node2)stack.Pop();

 

    public class MyClass<T>
    {
        public delegate void GenericDelegate(T t);
        public void SomeMethod(T t)
        {
 
        }
    }
    public GenericMethodDemo()
    {
        MyClass<int> obj = new MyClass<int>();
        MyClass<int>.GenericDelegate del;
        del = new MyClass<int>.GenericDelegate(obj.SomeMethod);
        del(3);
    }

上边的代码在编译时是全然没难题的,但由于Push了一个Node1类型的多寡,但在Pop时却供给改变为Node2类型,这将现出程序运营时的类型转变卓殊,但却逃离了编写翻译器的反省。

//实例化只好保留string类型的类

澳门新萄京官方网站 31

本着object类型栈的标题,我们引进泛型,他能够优雅地减轻那一个主题素材。泛型用用三个由此的数据类型T来取代object,在类实例化时钦点T的体系,运营时(Runtime)自动编写翻译为本地代码,运营效能和代码品质都有极大升高,何况保障数据类型安全。

Stack<string> b = new Stack<string>(100);

    委托推理:C#2.0令你能够将艺术引用的一向分配转换为委托变量。将上面的代码改动如下

使用泛型
上边是用泛型来重写下边包车型客车栈,用多少个通用的多寡类型T来作为三个占位符,等待在实例化时用二个实在的连串来代替。让我们来探视泛型的威力:

b.Push(10);    //这一行编写翻译不通过,因为类b只接受string类型的多寡

澳门新萄京官方网站 32

public class Stack

      b.Push("8888");

public class MyClass<T>
    {
        public delegate void GenericDelegate(T t);
        public void SomeMethod(T t)
        {
 
        }
    }
    public GenericMethodDemo()
    {
        MyClass<int> obj = new MyClass<int>();
        MyClass<int>.GenericDelegate del;

{

    private T[] m_item;

    public T Pop(){...}

    public void Push(T item){...}

    public Stack(int i)

    {

        this.m_item = new T[i];

    }

string y = b.Pop();

        //委托推理
      del = obj.SomeMethod;
        del(3);
     }    

}

 

澳门新萄京官方网站 33

类的写法不变,只是引入了通用数据类型T就能够适用于别的数据类型,况且类型安全的。这一个类的调用方法:

那么些类和object完结的类有一同差异的差别:

    泛型委托的自律:委托级其他约束只在宣称委托变量和实例化委托时行使,类似于在等级次序和办法的功用范围中实施的其他任何约束。

//实例化只可以保留int类型的类

1.       他是连串安全的。实例化了int类型的栈,就不能够管理string类型的数目,其余数据类型也一律。

泛型和反光

Stack

2.       没有须要装箱和折箱。那一个类在实例化时,根据所传诵的数据类型生花费地代码,本地代码数据类型已规定,所以不要求装箱和折箱。

    在Net2.0中路,扩张了反光以帮助泛型参数。类型Type未来得以代表带有一定项目的实参(或绑定类型)或未钦赐类型的泛型(或称未绑定类型)。像C#1.1中那样,您能够透过选拔typeof运算符或透过调用各个品种帮助的GetType()来获得其余类型的Type。代码如下:

  a.Push(10);

  a.Push("8888"); //这一行编译不通过,因为类a只接收int类型的数据

  int x = a.Pop();

3.       无需类型调换。

 LinkedList<int> list = new LinkedList<int>();
 Type type1 = typeof(LinkedList<int>);
 Type type2 = list.GetType();
 Response.Write(type1 == type2);

//实例化只可以保留string类型的类

 

     typeof和GetType()也足以对泛型参数举办操作,如下

Stack

泛型类实例化的说理
C#泛型类在编写翻译时,先生成人中学等代码IL,通用类型T只是多个占位符。在实例化类时,依据用户钦命的数据类型取代T并由即时编写翻译器(JIT)生开支地代码,那个地方代码中曾经应用了实在的数据类型,等同于用实际类型写的类,所以不一致的密闭类的地点代码是不平等的。依据这几个规律,我们能够如此以为:

澳门新萄京官方网站 34

b.Push(10); //这一行编写翻译不经过,因为类b只接收string类型的数目

泛型类的不如的密封类是各自分裂的数据类型。

public class MyClass<T>
{
    public void SomeMethod(T t)
    {
        Type type = typeof(T);
        HttpContext.Current.Response.Write(type==t.GetType());
    }
}

  b.Push("8888");

例:Stack<int>和Stack<string>是四个精光未有别的涉及的类,你能够把她看成类A和类B,那么些解释对泛型类的静态成员的明白有十分大帮扶。

澳门新萄京官方网站 35

string y = b.Pop();

 

    typeof还足以对未绑定的泛型进行操作,代码如下

这么些类和object完成的类有完全不一样的不一致:

泛型类中数据类型的自律
技师在编排泛型类时,总是会对通用数据类型T举行有意或下意识地有假想,也即是说那一个T一般的话是不能够适应全数品类,但怎么界定调用者传入的数据类型呢?那就必要对传播的数据类型举办约束,约束的点子是钦赐T的先世,即持续的接口或类。因为C#的单根承继性,所以约束能够有四个接口,但最多只好有一个类,何况类必须在接口以前。那时就用到了C#2.0的新增加关键字:

澳门新萄京官方网站 36

  1. 她是项目安全的。实例化了int类型的栈,就不可能管理string类型的数目,其余数据类型也同样。

  2. 毋庸装箱和折箱。这几个类在实例化时,依照所传颂的数据类型生开销地代码,本地代码数据类型已规定,所以不必装箱和折箱。

  3. 无须类型转变。

public class Node<T, V> where T : Stack, IComparable

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            Type unboundType = typeof(MyClass<>);
            Response.Write(unboundType.ToString());
        }
    }

泛型类实例化的驳斥
C#泛型类在编写翻译时,先生成人中学等代码IL,通用类型T只是贰个占位符。在实例化类时,依据用户内定的数据类型取代T并由即时编写翻译器(JIT)生花费地代码,这些地点代码中已经应用了实际的数据类型,等同于用实际类型写的类,所以分裂的密封类的本地代码是不相同的。依照这几个原理,大家能够如此以为:

        where V: Stack

    public class MyClass<T>
    {
        public void SomeMethod(T t)
        {
            Type type = typeof(T);
            HttpContext.Current.Response.Write(type==t.GetType());
        }
    }

泛型类的不及的密封类是分别分裂的数据类型。

    {...}

澳门新萄京官方网站 37

例:Stack

以上的泛型类的牢笼注解,T必须是从Stack和IComparable继承,V必须是Stack或从Stack承继,否则将不恐怕透过编写翻译器的档期的顺序检查,编写翻译退步。

    请小心"<>"的用法。要对含有八个类型参数的未绑定泛型类举办操作,请在"<>"中运用","

泛型类中数据类型的牢笼
程序猿在编排泛型类时,总是会对通用数据类型T进行有意或下意识地有假想,也正是说这几个T一般的话是不能够适应全体类别,但怎么样界定调用者传入的数据类型呢?那就须求对传播的数据类型进行封锁,约束的法子是钦赐T的祖宗,即一而再的接口或类。因为C#的单根承袭性,所以约束能够有四个接口,但最四只好有三个类,並且类必须在接口以前。那时就用到了C#2.0的新增添关键字:

通用类型T未有特指,但因为C#中持有的类都是从object承继来,所以他在类Node的编辑撰写中只可以调用object类的形式,那给程序的编写形成了劳碌。例如你的类设计只供给支持二种数据类型int和string,並且在类中供给对T类型的变量相当大小,但这个却不可能完毕,因为object是未曾比一点都不小小的主意的。 精晓决那一个难题,只需对T实行IComparable约束,那时在类Node里就足以对T的实例试行CompareTo方法了。那么些标题能够扩充到其余用户自定义的数据类型。

    Type类中增添了新的办法和性格,用于提供有关该品种的泛型方面包车型大巴反光消息,见MSDN。

public class Node<T, V> where T : Stack, IComparable

假诺在类Node里须求对T重新开始展览实例化该怎么办呢?因为类Node中不精晓类T到底有哪些构造函数。为了化解那些主题素材,须求使用new约束:

.net泛型约束  

所谓泛型,即通过参数化类型来达成在同样份代码上操作各个数据类型。泛型编制程序是一种编制程序范式,它利用“参数化类型”将品种抽象化,进而完成更为灵活的复用。

在概念泛型类时,能够对客户端代码可以在实例化类时用来项目参数的门类体系施加限制。假若客户端代码尝试利用某些约束所不一样意的品种来实例化类,则会发出编写翻译时不当。那个限制称为约束。约束是使用 where 上下文关键字钦命的。

下表列出了多样等级次序的自律:

约束 说明

T:struct

类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型。

T:class

类型参数必须是引用类型,包括任何类、接口、委托或数组类型。

T:new()

类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。

T:<基类名>

类型参数必须是指定的基类或派生自指定的基类。

T:<接口名称>

类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。

T:U

为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。这称为裸类型约束.

 ---------------------------------------

一.派生封锁

1.常见的

public class MyClass5<T> where T :IComparable { }

2.束缚放在类的实际上派生之后

public class B { }

public class MyClass6<T> : B where T : IComparable { }

3.方可承继四个基类和几个接口,且基类在接口前边

public class B { }

public class MyClass7<T> where T : B, IComparable, ICloneable { }

二.构造函数约束

1.常见的

public class MyClass8<T> where T :  new() { }

2.可以将构造函数约束和派生约束组合起来,前提是构造函数约束现身在约束列表的终极

public class MyClass8<T> where T : IComparable, new() { }

三.值约束

1.常见的

public class MyClass9<T> where T : struct { }

2.与接口约束同一时候利用,在最前头(不可能与基类约束,构造函数约束共同行使)

public class MyClass11<T> where T : struct, IComparable { }

四.引用约束

1.常见的

public class MyClass10<T> where T : class { }

五.四个泛型参数

 public class MyClass12<T, U> where T : IComparable  where U : class { }

六.承继和泛型

public class B<T>{ }

1. 在从泛型基类派生时,可以提供项目实参,实际不是基类泛型参数

    public class SubClass11 : B<int>
    { }

2.一旦子类是泛型,而非具体的门类实参,则足以选喇叭鸡屎果类泛型参数作为泛型基类的钦命项目

    public class SubClass12<R> : B<R>
    { }

3.在子类重复基类的牢笼(在接纳子类泛型参数时,必须在子类品级重复在基类品级规定的任何自律)
    public class B<T> where T : ISomeInterface { }
    public class SubClass2<T> : B<T> where T : ISomeInterface { }

4.构造函数约束
    public class B<T> where T : new()
    {
        public T SomeMethod()
        {
            return new T();
        }
    }
    public class SubClass3<T> : B<T> where T : new(){ }

七.泛型方法(C#2.0泛型机制支持在"方法声名上含蓄类型参数",那正是泛型方法)

1.泛型方法不仅能够富含在泛型类型中,又足以分包在非泛型类型中

public class MyClass5
    {

        public void MyMethod<T>(T t){ }
    }

2.泛型方法的宣示与调用

public class MyClass5
    {
        public void MyMethod<T>(T t){ }
    }
    public class App5
    {
        public void CallMethod()
        {
            MyClass5 myclass5 = new MyClass5();
            myclass5.MyMethod<int>(3);
        }
    }

3.泛型方法的重载

 //第一组重载
 void MyMethod1<T>(T t, int i){ }

 void MyMethod1<U>(U u, int i){ }

//第二组重载
 void MyMethod2<T>(int i){ }
 void MyMethod2(int i){ }

//第三组重载,固然有八个泛型参数
 void MyMethod3<T>(T t) where T : A { }
void MyMethod3<T>(T t) where T : B { }

//第四组重载

public class MyClass8<T,U>
    {
        public T MyMothed(T a, U b)
        {
            return a;
        }
        public T MyMothed(U a, T b)
        {
            return b;
        }
        public int MyMothed(int a, int b)
        {
            return a b;
        }
    }

4.泛型方法的覆写

(1)public class MyBaseClass1
    {
        public virtual void MyMothed<T>(T t) where T : new() { }
    }
    public class MySubClass1:MyBaseClass1
    {
        public override void MyMothed<T>(T t) //不可能重复任何约束
        { }
    }

(2)public class MyBaseClass2
    {
        public virtual void MyMothed<T>(T t)
        { }
    }
    public class MySubClass2 : MyBaseClass2
    {
        public override void MyMothed<T>(T t) //重新定义泛型参数T
        { }
    }

八.虚构方法

public class BaseClass4<T>
    {
        public virtual T SomeMethod()
        {
            return default(T);
        }
    }
    public class SubClass4 : BaseClass4<int> //使用实参承继的时候方法要选拔实参的品类
    {
        public override int SomeMethod()
        {
            return 0;
        }
    }

    public class SubClass5<T> : BaseClass4<T> //使用泛型承袭时,方法也是泛型
    {
        public override T SomeMethod()
        {
            return default(T);
        }
    }

九.编写翻译器只同意将泛型参数隐式强制调换来Object 或约束钦命的种类

class MyClass<T> where T : BaseClass, ISomeInterface
    {
        void SomeMethod(T t)
        {
            ISomeInterface obj1 = t;
            BaseClass obj2 = t;
            object obj3 = t;
        }
    }

变通方法:使用一时的 Object 变量,将泛型参数强制调换成其余任何项目

class MyClass2<T>
    {
        void SomeMethod(T t)
        {
            object temp = t;
            BaseClass obj = (BaseClass)temp;
        }
    }

十.编译器允许你将泛型参数字彰显式强制转换来其他任何接口,但不能将其转移到类

class MyClass1<T>
    {
        void SomeMethod(T t)
        {
            ISomeInterface obj1 = (ISomeInterface)t;  
            //BaseClass obj2 = (BaseClass)t;           //不能够经过编写翻译
        }
    }

 

十一.行使一时的 Object 变量,将泛型参数强制转换来其他任何项目

class MyClass2<T>
    {
        void SomeMethod(T t)
        {
            object temp = t;
            BaseClass obj = (BaseClass)temp;
        }
    }

十二.使用is和as运算符

public class MyClass3<T>
    {
        public void SomeMethod(T t)
        {
            if (t is int) { }
            if (t is LinkedList<int>) { }
            string str = t as string;
            if (str != null) { }
            LinkedList<int> list = t as LinkedList<int>;
            if (list != null) { }
        }
    }

    where V: Stack

{...}

public class Node<T, V> where T : Stack, new()

上述的泛型类的羁绊评释,T必须是从Stack和IComparable承继,V必须是Stack或从Stack承接,不然将不能够通过编写翻译器的门类检查,编写翻译失利。

        where V: IComparable

通用类型T未有特指,但因为C#中装有的类都是从object承袭来,所以她在类Node的编写中不得不调用object类的办法,那给程序的编辑创作立成了狼狈。比方您的类设计只要求帮忙三种数据类型int和string,何况在类中须求对T类型的变量比相当的大小,但这个却力所比不上兑现,因为object是一贯不相当大小的措施的。 了消除那几个主题素材,只需对T举行IComparable约束,那时在类Node里就能够对T的实例实施CompareTo方法了。那一个难题得以扩张到其他用户自定义的数据类型。

急需专注的是,new约束只好是无参数的,所以也供给相应的类Stack必须有二个无参构造函数,否则编写翻译退步。

假设在类Node里必要对T重新展开实例化该咋做吧?因为类Node中不知晓类T到底有怎样构造函数。为了消除那一个标题,必要利用new约束:

C#中数据类型有两大类:援用类型和值类型。援引类型如享有的类,值类型一般是言语的最基本类型,如int, long, struct等,在泛型的牢笼中,大家也能够大面积地范围类型T必须是引用类型或必须是值类型,分别对应的要害字是class和struct:

public class Node<T, V> where T : Stack, new()

public class Node<T, V> where T : class

    where V: IComparable

        where V: struct

要求留意的是,new约束只可以是无参数的,所以也需求对应的类Stack必须有二个无参构造函数,不然编写翻译退步。

 

C#中数据类型有两大类:引用类型和值类型。援用类型如享有的类,值类型一般是语言的最主题类型,如int, long, struct等,在泛型的束缚中,大家也足以大规模地界定类型T必须是援引类型或必须是值类型,分别对应的第一字是class和struct:

泛型方法
泛型不只能成效在类上,也可单独用在类的点子上,他可依据章程参数的档期的顺序自动适应种种参数,那样的主意叫泛型方法。看下边包车型客车类:

public class Node<T, V> where T : class

public class Stack2

    where V: struct

    {

泛型方法
泛型不仅可以功用在类上,也可单独用在类的法子上,他可依照办法参数的等级次序自动适应种种参数,那样的办法叫泛型方法。看上边包车型地铁类:

        public void Push<T>(Stack<T> s, params T[] p)

public class Stack2

        {

{

    public void Push<T>(Stack<T> s, params T[] p)

    {

        foreach (T t in p)

        {

            s.Push(t);

        }

    }

            foreach (T t in p)

}

            {

本来的类Stack一回只好Push多少个数额,这几个类Stack2扩充了Stack的功能(当然也得以直接写在Stack中),他得以二次把七个数据压入Stack中。个中Push是一个泛型方法,这么些主意的调用示比如下:

                s.Push(t);

Stack

            }

Stack2 x2 = new Stack2();

x2.Push(x, 1, 2, 3, 4, 6);

string s = "";

for (int i = 0; i < 5; i  )

{

    s  = x.Pop().ToString();

}    //至此,s的值为64321

        }

泛型中的静态成员变量
在C#1.x中,大家精晓类的静态成员变量在分化的类实例间是分享的,何况她是通过类名访谈的。C#2.0中由于引入了泛型,导致静态成员变量的建制出现了有的变动:静态成员变量在同一密闭类间分享,不一致的查封类间不分享。

}

那也非常轻巧掌握,因为差异的密闭类固然有平等的类名称,但鉴于个别传入了分化的数据类型,他们是一心两样的类,举例:

原本的类Stack二遍只能Push八个数码,这几个类Stack2扩展了Stack的魔法(当然也能够一贯写在Stack中),他能够壹遍把四个数据压入Stack中。当中Push是三个泛型方法,这一个法子的调用示举例下:

Stack

Stack<int> x = new Stack<int>(100);

Stack

    Stack2 x2 = new Stack2();

Stack

    x2.Push(x, 1, 2, 3, 4, 6);

类实例a和b是毫无二致品种,他们中间分享静态成员变量,但类实例c却是和a、b完全两样的连串,所以不可能和a、b分享静态成员变量。

    string s = "";

泛型中的静态构造函数
静态构造函数的法规:只可以有二个,且不能够有参数,他不得不被.NET运维时自动调用,而无法人工资调解用。

    for (int i = 0; i < 5; i )

泛型中的静态构造函数的原理和非泛型类是同样的,只需把泛型中的区别的密封类精通为不一致的类就能够。以下两种状态可激发静态的构造函数:

    {

  1. 特定的封闭类第贰回被实例化。

  2. 特定密封类中任一静态分子变量被调用。

        s = x.Pop().ToString();

泛型类中的方法重载
办法的重载在.Net Framework中被大量选拔,他供给重载具有分歧的签字。在泛型类中,由于通用类型T在类编排时并不明确,所以在重载时某些注意事项,那么些事项大家经过以下的例证表明:

    }    //至此,s的值为64321

public class Node<T, V>

   

{

    public T add(T a, V b)          //第一个add

    {

        return a;

    }

    public T add(V a, T b)          //第二个add

    {

        return b;

    }

    public int add(int a, int b)    //第三个add

    {

        return a   b;

    }

 

}

泛型中的静态成员变量
在C#1.x中,大家知晓类的静态成员变量在差异的类实例间是共享的,何况她是经过类名访谈的。C#2.0中由于引入了泛型,导致静态成员变量的建制出现了有个别转变:静态成员变量在一样密闭类间分享,不一致的密闭类间不分享。

地方的类很显眼,即便T和V都传入int的话,多少个add方法将有着一样的签订契约,但以此类还能透过编写翻译,是还是不是会引起调用混淆就要这些类实例化和调用add方法时判定。请看下边调用代码:

那也非常轻松驾驭,因为不相同的密封类尽管有雷同的类名称,但由于各自传入了区别的数据类型,他们是点点滴滴差别的类,比方:

Node<int, int> node = new Node<int, int>();

Stack<int> a = new Stack<int>();

object x = node.add(2, 11);

Stack<int> b = new Stack<int>();

本条Node的实例化引起了八个add具备同样的签订契约,但却能调用成功,因为他事先相配了第多少个add。但尽管剔除了第多个add,上面包车型客车调用代码则无从编写翻译通过,提醒方法产生的歪曲,因为运维时非常的小概在首先个add和首个add之间选拔。

Stack<long> c = new Stack<long>();

Node<string, int> node = new Node<string, int>();

类实例a和b是同一品种,他们中间共享静态成员变量,但类实例c却是和a、b完全两样的门类,所以不可能和a、b分享静态成员变量。

    object x = node.add(2, "11");

泛型中的静态构造函数
静态构造函数的法规:只可以有多少个,且不能够有参数,他不得不被.NET运维时自动调用,而无法人工资调度用。

这两行调用代码可科学编写翻译,因为传播的string和int,使两个add具备分化的签订契约,当然能找到独一匹配的add方法。

泛型中的静态构造函数的规律和非泛型类是一模一样的,只需把泛型中的区别的密封类明白为差别的类就可以。以下三种情况可激发静态的构造函数:

由以上示例可见,C#的泛型是在实例的议程被调用时检查重载是或不是发生模糊,实际不是在泛型类自己编写翻译时检查。同有的时候间还搜查缉获二个首要尺度:

1.       特定的密封类第二回被实例化。

当一般方法与泛型方法具有同等的具名时,会覆盖泛型方法。

2.       特定密封类中任一静态成员变量被调用。

泛型类的不二法门重写
格局重写(override)的主要难点是方法具名的鉴定识别准绳,在那点上他与办法重载一样,请参谋泛型类的主意重载。

 

泛型的施用限制
正文主假设在类中陈说泛型,实际上,泛型还是能用在类格局、接口、结构(struct)、委托等地方使用,使用办法差不离一样,就不再陈诉。

泛型类中的方法重载
格局的重载在.Net Framework中被多量利用,他需要重载具有不一样的签署。在泛型类中,由于通用类型T在类编排时并不鲜明,所以在重载时不怎么注意事项,那么些事项大家经过以下的事例表明:

小结
C# 泛型是开拓工具库中的三个珍贵和稀有之宝。它们得以提升品质、类型安全和品质,收缩重复性的编制程序职分,简化总体编制程序模型,而这一切都是通过优雅的、可读性强的语法达成的。固然C# 泛型的根底是 C 模板,但 C# 通过提供编写翻译时安全和帮衬将泛型进步到了二个新水平。C# 利用了两等第编写翻译、元数据以及诸如约束和一般方法之类的创新性的概念。不容争辩,C# 的今后版本将继续前行泛型,以便加多新的法力,并且将泛型扩大到诸如数码访问或本地化之类的任何

public class Node<T, V>

.NET Framework 领域。

在C#2.0中,方法能够定义特定于其执行范围的泛型参数,如下所示:
public class MyClass

     //此方法也可不指定方法参数
    public void MyMethod<X>() 
     {
         //
    }
 }    

即使包含类不适用泛型参数,你也可以定义方法特定的泛型参数,如下所示:

public class MyClass
 {
     //指定MyMethod方法用以执行类型为X的参数
    public void MyMethod<X>(X x) 
     {
         //
    }

     //此方法也可不指定方法参数
    public void MyMethod<X>() 
     {
         //
    }
 } 

注意:属性和索引器不能指定自己的泛型参数,它们只能使用所属类中定义的泛型参数进行操作。

在调用泛型方法的时候,你可以提供要在调用场所使用的类型,如下所示:

//调用泛型方法
MyClass myClass = new MyClass();
myClass.MyMethod

泛型推理:在调用泛型方法时,C#编译器足够聪明,基于传入的参数类型来推断出正确的类型,并且它允许完全省略类型规范,如下所示:

//泛型推理机制调用泛型方法
MyClass myClass = new MyClass();
myClass.MyMethod(3);

注意:泛型方法无法只根据返回值的类型推断出类型,代码如下:

 public GenericMethodDemo()
  {        
     MyClass myClass = new MyClass();
     /****************************************************
     无法从用法中推理出方法“GenericMethodDemo.MyClass.MyMethod<T>()”的类型参数。
    请尝试显式指定类型参数。
    ***************************************************/
     int number = myClass.MyMethod();
  }

 public class MyClass
 {
     public T MyMethod<T>() 
     {
         //
    }
 } 

泛型方法中泛型参数的约束,如下:

public class MyClass
 {

     public void MyMethod<X>(X x) where X:IComparable<X>
     {
         //
    }
 }


您无法为类级别的泛型参数提供方法级别的约束。类级别泛型参数的所有约束都必须在类作用范围中定义,代码如下所示

public class MyClass<T>
 {

     public void MyMethod<X>(X x,T t) where X:IComparable<X> where T:IComparer<T>
     {
         //
    }
 } 

而上面包车型地铁代码是天经地义的

public class MyClass<T> where T:IComparable<T>
 {

     public void MyMethod<X>(X x,T t) where X:IComparable<X> 
     {
         //
    }
 } 

泛型参数虚方法的重写:子类方法必须重新定义该方法特定的泛型参数,代码如下

public class MyBaseClass
 {
     public virtual void SomeMethod<T>(T t)
     {
         //
    }
 }
 public class MyClass :MyBaseClass
 {
     public override void SomeMethod<X>(X x)
     {

     }
 } 

与此同期子类中的泛型方法不能够重新基类泛型方法的束缚,那点和泛型类中的虚方法重写是有分其余,代码如下

public class MyBaseClass
 {
     public virtual void SomeMethod<T>(T t) where T:new()
     {
         //
    }
 }
 public class MyClass :MyBaseClass
 {
     //正确写法
    public override void SomeMethod<X>(X x)
     {

     }

     ////错误 重写和显式接口实现方法的约束是从基方法继承的,因此不能直接指定这些约束
    //public override void SomeMethod<X>(X x) where X:new()
     //{

     //}
} 

子类方法调用虚拟方法的基类实现:它必须指定要代替泛型基础方法类型所使用的类型实参。你可以自己显式的指定它,也可以依靠类型推理(如果可能的话)代码如下:

public class MyBaseClass
 {
     public virtual void SomeMethod<T>(T t) where T:new()
     {
         //
    }
 }
 public class MyClass :MyBaseClass
 {
     //正确写法
    public override void SomeMethod<X>(X x)
     {
         base.SomeMethod<X>(x);
         base.SomeMethod(x);
     }
 } 

泛型委托

在某个类中定义的委托可以使用该类的泛型参数,代码如下

public class MyClass<T>
 {
     public delegate void GenericDelegate(T t);
     public void SomeMethod(T t)
     {

     }
 }
 public GenericMethodDemo()
 {
     MyClass<int> obj = new MyClass<int>();
     MyClass<int>.GenericDelegate del;
     del = new MyClass<int>.GenericDelegate(obj.SomeMethod);
     del(3);
 } 

委托推理:C#2.0使你可以将方法引用的直接分配转变为委托变量。将上面的代码改造如下

public class MyClass

     }
 }
 public GenericMethodDemo()
 {
     MyClass<int> obj = new MyClass<int>();
     MyClass<int>.GenericDelegate del;

     //委托推理
  del = obj.SomeMethod;
     del(3);
  }     

泛型委托的约束:委托级别的约束只在声明委托变量和实例化委托时使用,类似于在类型和方法的作用范围中实施的其他任何约束。

泛型和反光

在Net2.0当中,扩展了反射以支持泛型参数。类型Type现在可以表示带有特定类型的实参(或绑定类型)或未指定类型的泛型(或称未绑定类型)。像C#1.1中那样,您可以通过使用typeof运算符或通过调用每个类型支持的GetType()来获得任何类型的Type。代码如下:

LinkedList

 typeof和GetType()也可以对泛型参数进行操作,如下

public class MyClass

typeof还可以对未绑定的泛型进行操作,代码如下

protected void Page_Load(object sender, EventArgs e)
 {
     if (!IsPostBack)
     {
         Type unboundType = typeof(MyClass<>);
         Response.Write(unboundType.ToString());
     }
 }

 public class MyClass<T>
 {
     public void SomeMethod(T t)
     {
         Type type = typeof(T);
         HttpContext.Current.Response.Write(type==t.GetType());
     }
 } 


请注意"<>"的用法。要对带有多个类型参数的未绑定泛型类进行操作,请在"<>"中使用","
Type类中添加了新的方法和属性,用于提供有关该类型的泛型方面的反射信息,见MSDN。

.net泛型约束

所谓泛型,即因此参数化类型来兑现在长期以来份代码上操作四种数据类型。泛型编制程序是一种编制程序范式,它接纳“参数化类型”将品种抽象化,进而达成更灵活的复用。

在概念泛型类时,能够对客户端代码能够在实例化类时用于项目参数的类型连串施加限制。假诺客户端代码尝试接纳有些约束所不容许的门类来实例化类,则会生出编写翻译时不当。那一个限制称为约束。约束是运用 where 上下文关键字内定的。

下表列出了五种类型的封锁:

封锁表达:

T:struct

类型参数必须是值类型。能够钦命除 Nullable 以外的别样值类型。

T:class

花色参数必须是援引类型,饱含任何类、接口、委托或数组类型。

T:new()

项目参数必须怀有无参数的国有构造函数。当与另外约束共同行使时,new() 约束必须最终钦赐。

T:<基类名>

类型参数必须是点名的基类或派生自内定的基类。

T:<接口名称>

类型参数必须是点名的接口或促成钦点的接口。能够内定三个接口约束。约束接口也得以是泛型的。

T:U

为 T 提供的连串参数必须是为 U 提供的参数或派生自为 U 提供的参数。那叫做裸类型约束.


一.派生羁绊

1.常见的

public class MyClass5

2.约束放在类的其实派生之后

public class B { }

public class MyClass6

3.足以承袭贰个基类和五个接口,且基类在接口前边

public class B { }

public class MyClass7

二.构造函数约束

1.常见的

public class MyClass8

2.可以将构造函数约束和派生约束组合起来,前提是构造函数约束出现在封锁列表的末梢

public class MyClass8

三.值约束

1.常见的

public class MyClass9

2.与接口约束同有时候使用,在最前边(不能够与基类约束,构造函数约束共同行使)

public class MyClass11

四.引用约束

1.常见的

public class MyClass10

五.多个泛型参数

public class MyClass12<T, U> where T : IComparable where U : class { }

六.继承和泛型

public class B

  1. 在从泛型基类派生时,能够提供项目实参,实际不是基类泛型参数

    public class SubClass11 : B

2.假设子类是泛型,而非具体的门类实参,则足以利用子类泛型参数作为泛型基类的钦赐项目

public class SubClass12<R> : B<R>
 { }

3.在子类重复基类的约束(在动用子类泛型参数时,必须在子类等级重复在基类等第规定的别的自律)
public class B

4.构造函数约束
澳门新萄京官方网站,public class B

七.泛型方法(C#2.0泛型机制援助在"方法声名上带有类型参数",那正是泛型方法)

1.泛型方法既可以够涵盖在泛型类型中,又能够包含在非泛型类型中

public class MyClass5
{

    public void MyMethod<T>(T t){ }
 }

2.泛型方法的宣示与调用

public class MyClass5
{
public void MyMethod

3.泛型方法的重载

//第一组重载
void MyMethod1

void MyMethod1(U u, int i){ }

//第二组重载
void MyMethod2

//第三组重载,借使有四个泛型参数
void MyMethod3

//第四组重载

public class MyClass8<T,U>
{
public T MyMothed(T a, U b)
{
return a;
}
public T MyMothed(U a, T b)
{
return b;
}
public int MyMothed(int a, int b)
{
return a b;
}
}

4.泛型方法的覆写

(1)public class MyBaseClass1
{
public virtual void MyMothed

(2)public class MyBaseClass2
{
public virtual void MyMothed

八.设想方法

public class BaseClass4

public class SubClass5<T> : BaseClass4<T> //使用泛型继承时,方法也是泛型
{
     public override T SomeMethod()
     {
         return default(T);
     }
 }

九.编写翻译器只允许将泛型参数隐式强制调换来 Object 或约束钦点的门类

class MyClass

变通方法:使用有时的 Object 变量,将泛型参数强制转换来其余任何项目

class MyClass2

十.编写翻译器允许你将泛型参数字显示式强制转变来别的任何接口,但不能够将其转移到类

class MyClass1

十一.行使不经常的 Object 变量,将泛型参数强制转形成另外任何项目

class MyClass2

十二.使用is和as运算符

public class MyClass3

    {

        public T add(T a, V b)          //第一个add

        {

            return a;

        }

        public T add(V a, T b)          //第二个add

        {

            return b;

        }

        public int add(int a, int b)    //第三个add

        {

            return a b;

        }

}

地点的类很鲜明,纵然T和V都传入int的话,三个add方法将具有同样的签订契约,但以此类还能通过编写翻译,是还是不是会引起调用混淆就要那几个类实例化和调用add方法时判定。请看下边调用代码:

Node<int, int> node = new Node<int, int>();

    object x = node.add(2, 11);

本条Node的实例化引起了八个add具有一样的签署,但却能调用成功,因为他事先相配了第四个add。但万一剔除了第多少个add,上边包车型大巴调用代码则无从编译通过,提示方法发生的模糊,因为运转时无法在第一个add和第一个add之间接选举择。

Node<string, int> node = new Node<string, int>();

        object x = node.add(2, "11");

   这两行调用代码可科学编写翻译,因为传播的string和int,使多少个add具备不一致的签字,当然能找到独一相称的add方法。

由上述示例可见,C#的泛型是在实例的艺术被调用时检查重载是还是不是发生模糊,实际不是在泛型类本身编写翻译时检查。同有时候还得出一个生死攸关尺度:

当一般方法与泛型方法具备同等的签署时,会覆盖泛型方法。

 

泛型类的议程重写
艺术重写(override)的主要难题是格局签字的辨认准绳,在那点上她与方法重载同样,请参考泛型类的法子重载。

 

泛型的选择限制
正文主如果在类中描述泛型,实际上,泛型还是能用在类措施、接口、结构(struct)、委托等地方运用,使用方法大概一样,就不再陈说。

小结
C# 泛型是开荒工具库中的贰个珍贵和稀有之宝。它们得以加强质量、类型安全和品质,裁减重复性的编制程序职务,简化总体编制程序模型,而这一切都以通过优雅的、可读性强的语法完成的。就算C# 泛型的底蕴是 C 模板,但 C# 通过提供编写翻译时安全和帮助将泛型升高到了二个新水平。C# 利用了两等级编写翻译、元数据以及诸如约束和一般方法之类的创新性的定义。没有疑问,C# 的今后版本将持续上扬泛型,以便增添新的成效,况兼将泛型扩大到诸如数码访谈或本地化之类的其余.NET Framework 领域。

本文由澳门新萄京官方网站发布于www.8455.com,转载请注明出处:澳门新萄京官方网站:什么是泛型,泛型总结

关键词: