前言

所谓泛型,即通过参数化类型来兑现在同样份代码上操作多样数据类型。

泛型编制程序是一种编制程序范式,它应用“参数化类型”将品种抽象化,从而落成更为灵活的复用。在概念泛型类时,在对客户端代码能够在实例化类时,能够用项目参数的种类类别施加限制。在搭建底层框架时,是最常见的编制程序方式。

 

来自Hauk的文章 C#
泛型编制程序之泛型类、泛型方法、泛型约束

泛型方法

一、List

泛型类

泛型类范例:

namespace ORDER.SYSTEM.DAL.Data
{
    public abstract class AgentBase<T> where T : class, new()
    {

        //私有实例
        private static T _instance;

        // 定义一个标识确保线程同步
        private static readonly object locker = new object();

        /// <summary>
        /// 返回单例对象
        /// </summary>
        /// <returns></returns>
        public static T Instance()
        {
            if (_instance == null)
            {
                lock (locker)
                {
                    if (_instance == null)
                    {
                        switch (typeof(T).FullName)
                        {
                            case "ORDER.SYSTEM.BLL.TextImpl":
                                _instance = new T(); //此处的T表示命名空间的下的某个类被托管或重写,只保留功能
                                break;
                            default:
                                _instance = new T();
                                break;
                        }
                    }
                }
            }
            return _instance;
        }

    }
}

泛型类的指标是为着约束泛型方法传参数类型或回到值类型。

 

  

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

壹)、表示可通过索引访问的对象的强类型列表;提供用于对列表实行搜寻、排序和操作的方法。
二)、是ArrayList类的泛型等效类。
3)、能够选用二个整数索引访问此集聚中的成分;索引从零 初始。
四)、还不错null空引用(VB中的Nothing)。
5)、允许再一次成分

泛型方法

在C# 贰.0中,方法能够定义特定于其履行范围的泛型参数,如下所示:

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

    //此方法也可不指定方法参数
    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<int>(3);

 

泛型推理:

在调用泛型方法时,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>
    {
        //
    }
}

 

  所谓泛型,即通过参数化类型来兑今后相同份代码上操作种种数据类型。

金沙注册送58 1

二、List

.NET泛型约束

若果客户端代码尝试选用有个别约束所不容许的种类来实例化类,则会时有产生编写翻译时不当。这么些限制称为约束。约束是接纳where 上下文关键字钦定的。

下表列出了5体系型的羁绊:

 

约束 说明

T:struct

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

T:class

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

T:new()

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

T:<基类名>

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

T:<接口名称>

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

T:U

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

 

 

 

派生约束

1.常见的

public class MyClass5 where T :IComparable { }

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

public class B { }

public class MyClass6 : B where T : IComparable { }

叁.能够一而再叁个基类和多少个接口,且基类在接口前边

public class B { }

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

 

构造函数约束

1.常见的

public class MyClass8 where T : new() { }

二.得以将构造函数约束和派生约束组合起来,前提是构造函数约束出以后封锁列表的末段

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

 

值约束

1.常见的

public class MyClass9 where T : struct { }

二.与接口约束同时接纳,在最前方(不可能与基类约束,构造函数约束共同行使)

public class MyClass11 where T : struct, IComparable { }

 

引用约束

常见的

public class MyClass10 where T : class { }

多少个泛型参数

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

 

 

PS:欢迎扫描下方二维码,参与QQ群

金沙注册送58 2

 

作者:Jacky

来源:

扬言:本文版权归作者和腾讯网共有,欢迎转发,但未经小编同意必须保留此段注解,且在篇章页面分明地方给出最初的小说连接,不然保留追究法律权利的义务。

  泛型编制程序是一种编制程序范式,它利用“参数化类型”将项目抽象化,从而完成更灵活的复用。在概念泛型类时,在对客户端代码能够在实例化类时,能够用项目参数的花色连串施加限制。

    public class MyClass<T>
    {
        //钦定MyMethod方法用以实施项目为X的参数
        public void MyMethod<X>(X x) 
        {
            //金沙注册送58 3
        }

List

泛型方法

在C#
2**.0**中,方法能够定义特定于其举行范围的泛型参数,如下所示:

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

    //此方法也可不指定方法参数
    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<int>(3);

 

泛型推理:

在调用泛型方法时,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 void MyMethod<X>() 
        {
            //金沙注册送58 4
        }
    }   

List

泛型类

心中无数为类级别的泛型参数提供情势级别的约束。类级别泛型参数的保有约束都必须在类功用范围中定义,代码如下所示

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);
    }
}

 

金沙注册送58 5

List

泛型委托

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

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#二.0使您能够将艺术引用的直接分配转变为委托变量。将地点的代码改造如下

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 = obj.SomeMethod;
    del(3);
 }  

泛型委托的羁绊

寄托级其余自律只在注脚委托变量和实例化委托时选择,类似于在项目和办法的效用范围中进行的其他任何约束。

泛型和反光

在Net二.0中级,扩大了反光以支撑泛型参数。类型Type现在得以表示带有一定类型的实参(或绑定类型)或未钦命类型的泛型(或称未绑定类型)。像C#1.第11中学这样,您能够通过运用typeof运算符或透过调用各个门类支持的GetType()来赢得别的类型的Type。代码如下:

LinkedList<int> list = new LinkedList<int>();
 Type type1 = typeof(LinkedList<int>);
 Type type2 = list.GetType();
 Response.Write(type1 == type2);
 typeof和GetType()也可以对泛型参数进行操作,如下

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

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。

 

 

    尽管带有类不适用泛型参数,你也能够定义方法特定的泛型参数,如下所示:

三、List

.net泛型约束  

  假使客户端代码尝试运用有个别约束所不容许的门类来实例化类,则会时有发生编写翻译时不当。这一个限制称为约束。约束是行使
where 上下文关键字钦定的。

金沙注册送58 6

Capacity
获取或安装该内部数据结构在不调整大小的情事下能够容纳的因素总数。

一、 约束

  下表列出了七种档次的牢笼:

约束 说明

T:struct

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

T:class

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

T:new()

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

T:<基类名>

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

T:<接口名称>

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

T:U

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

 

    public class MyClass
    {
        //钦点MyMethod方法用以实施项目为X的参数
        public void MyMethod<X>(X x) 
        {
            //金沙注册送58 7
        }

Count
获取 List

 

        //此方法也可不钦定方法参数
        public void MyMethod<X>() 
        {
            //金沙注册送58 8
        }
    }

四、List

派生约束

1.常见的

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

2.羁绊放在类的实在派生之后

public
class B { }

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

三.得以一而再三个基类和四个接口,且基类在接口前边

public
class B { }

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

金沙注册送58 9

Add
将对象添加到 List

构造函数约束

1.常见的

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

二.能够将构造函数约束和派生约束组合起来,前提是构造函数约束出现在约束列表的结尾

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

    注意:属性和索引器不可能钦点本人的泛型参数,它们只可以接纳所属类中定义的泛型参数举办操作。

AddRange
将点名集合的成分添加到 List

值约束

1.常见的

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

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

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

    在调用泛型方法的时候,你能够提供要在调用场合采纳的连串,如下所示:

AsReadOnly
重回当前集合的只读 IList

引用约束

常见的

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

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

BinarySearch(T)
行使私下认可的相比较器在全方位已排序的 List

多个泛型参数

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

 

    泛型推理:在调用泛型方法时,C#编写翻译器丰富聪明,基于传入的参数类型来揆度出正确的种类,并且它同意完全省略类型规范,如下所示:

BinarySearch(T, IComparer

二、 继承和泛型

public
class B<T>{ }

一.
在从泛型基类派生时,能够提供品类实参,而不是基类泛型参数

   
public class SubClass11 : B<int>
    { }

二.只要子类是泛型,而非具体的连串实参,则能够使用子类泛型参数作为泛型基类的内定项目

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

三.在子类重复基类的牢笼(在行使子类泛型参数时,必须在子类级别重复在基类级别规定的任何自律)
    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(){
}

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

BinarySearch(Int32, Int32, T, IComparer

三、泛型方法

(C#二.0泛型机制接济在”方法声名上含蓄类型参数”,那正是泛型方法)

壹.泛型方法既能够涵盖在泛型类型中,又能够包罗在非泛型类型中

public class MyClass5
    {

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

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

public class MyClass5
{
    public void MyMethod<T>(T t){ }
}
public class App5
{
    public void CallMethod()
    {
        MyClass5 myclass5 = new MyClass5();
        myclass5.MyMethod<int>(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;
    }
}

 

四.泛型方法的覆写

(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
        { }
    }

    注意:泛型方法不能够只依据重回值的项目猜度出类型,代码如下:

Clear
从 List

4、虚拟方法

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);
    }
}

 

金沙注册送58 10

Contains
规定某成分是不是在 List

5、泛型参数隐式强制转换

编写翻译器只允许将泛型参数隐式强制转换成 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;
    }
}

 

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

ConvertAll

六、 泛型参数字展现式强制转换

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

 

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

 

 

    public class MyClass
    {
        public T MyMethod<T>() 
        {
            //金沙注册送58 11
        }
    }

CopyTo(T[])
将整个 List

七、 泛型参数强制转换成其余任何项目

动用一时的 Object 变量,将泛型参数强制转换来别的任何项目

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

 

金沙注册送58 12

Exists
确定 List

八、使用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) { }
    }
}

 

 

    泛型方法中泛型参数的牢笼,如下:

Find
招来与钦点谓词所定义的规格相匹配的因素,并重临整个 List

金沙注册送58 13

FindIndex(Predicate

    public class MyClass
    {
        
        public void MyMethod<X>(X x) where X:IComparable<X>
        {
            //金沙注册送58 14
        }
    }

ForEach
对 List

金沙注册送58 15

GetEnumerator
归来循环访问 List

   
您无法为类级别的泛型参数提供格局级其余牢笼。类级别泛型参数的装有约束都必须在类功效范围中定义,代码如下所示

IndexOf(T)
检索钦定的靶子,并回到整个 List

金沙注册送58 16

Insert
将成分插入 List

    public class MyClass<T>
    {
        
        public void MyMethod<X>(X x,T t) where X:IComparable<X> where T:IComparer<T>
        {
            //金沙注册送58 17
        }
    }

InsertRange
将聚合中的有些成分插入 List

金沙注册送58 18

LastIndexOf(T)
查找钦点的靶子,并重回整个 List

而下边包车型客车代码是没有错的

Remove
从 List

金沙注册送58 19

Reverse()
将整个 List

    public class MyClass<T> where T:IComparable<T>
    {
        
        public void MyMethod<X>(X x,T t) where X:IComparable<X> 
        {
            //金沙注册送58 20
        }
    }

Sort()
应用默许比较器对整个 List

金沙注册送58 21

伍、常用方法实例

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

(1)成立及开端化:
List

金沙注册送58 22

(贰)添加三个成分 List.Add(T item)
mlist.Add(“d”);

    public class MyBaseClass
    {
        public virtual void SomeMethod<T>(T t)
        {
            //金沙注册送58 23
        }
    }
    public class MyClass :MyBaseClass
    {
        public override void SomeMethod<X>(X x)
        {
            
        }
    }

(三)添加集合成分
string[] Arr2
={“f”,”g”.”h”};mlist.AddRange(Arr2);

金沙注册送58 24

(四)在index地方添加四个要素 Insert(int index,T item)
mlist.Insert(1,”p”);

并且子类中的泛型方法无法重复基类泛型方法的羁绊,那或多或少和泛型类中的虚方法重写是有分其余,代码如下

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

金沙注册送58 25

(六)删除成分
List.Remove(T item)
删去3个值mlist.Remove(“a”);

    public class MyBaseClass
    {
        public virtual void SomeMethod<T>(T t) where T:new()
        {
            //金沙注册送58 26
        }
    }
    public class MyClass :MyBaseClass
    {
        //正确写法
        public override void SomeMethod<X>(X x)
        {
            
        }

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

        ////错误 重写和显式接口完成形式的羁绊是从基方法继承的,因而不可能一向钦点那一个约束
        //public override void SomeMethod<X>(X x) where X:new()
        //{


        //}
    }

大家在编写程序时,平常遇到多个模块的法力十三分相像,只是叁个是处理int数据,另多个是拍卖string数据,或许别的自定义的数据类型,但大家并没有主意,只好分别写多个章程处理各样数据类型,因为方法的参数类型分化。有未有一种方法,在措施中传来通用的数据类型,那样不就足以统一代码了呢?泛型的出现就是专程化解那一个题材的。读完本篇文章,你会对泛型有更深的摸底。
为啥要使用泛型
为了掌握这么些标题,大家先看上面包车型客车代码,代码省略了部分剧情,但功用是兑现三个栈,这几个栈只可以处理int数据类型:

金沙注册送58 27

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];

    }

金沙注册送58 28

}

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

下边代码运营的很好,可是,当大家须要二个栈来保存string类型时,该咋做呢?很三个人都会想到把地点的代码复制一份,把int改成string不就行了。当然,那样做自身是绝非别的难点的,但五个好好的程序是不会这样做的,因为她想到若从此再须要long、Node类型的栈该如何做吗?还要再复制吗?优异的程序员会想到用三个通用的数据类型object来贯彻那几个栈:

金沙注册送58 30

public class Stack

泛型委托

{

    private object[] m_item;

    public object Pop(){...}

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

    public Stack(int i)

    {

        this.m_item = new[i];

    }



}

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

以此栈写的正确性,他非凡灵活,能够选择任何数据类型,可以说是一劳永逸。但完美地讲,也不是不曾缺陷的,重要表未来:

金沙注册送58 31

当Stack处理值类型时,会现出装箱、折箱操作,这将在托管堆上分配和回收多量的变量,若数据量大,则性能损失十二分沉痛。
在拍卖引用类型时,纵然尚无装箱和折箱操作,但将用到数据类型的威迫转换操作,扩充处理器的承担。
在数据类型的强制转换上还有更要紧的标题(假诺stack是Stack的八个实例):
Node1 x = new Node1();

    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);
    }

        stack.Push(x);

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

金沙注册送58 32

上边包车型客车代码在编写翻译时是截然没难点的,但鉴于Push了一个Node1类型的数码,但在Pop时却要求撤换为Node贰类型,那将出现程序运转时的类型转换至极,但却逃离了编译器的检查。

    委托推理:C#二.0使您能够将艺术引用的直白分配转变为委托变量。将地方的代码改造如下

本着object类型栈的标题,大家引进泛型,他能够优雅地化解那一个题材。泛型用用一个由此的数据类型T来代替object,在类实例化时钦点T的门类,运转时(Runtime)自动编译为本地代码,运营功能和代码品质都有相当的大升高,并且保障数据类型安全。

金沙注册送58 33

动用泛型
上面是用泛型来重写上面的栈,用3个通用的数码类型T来作为一个占位符,等待在实例化时用贰个实际的花色来顶替。让大家来探望泛型的威力:

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;

public class Stack

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

{

    private T[] m_item;

    public T Pop(){...}

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

    public Stack(int i)

    {

        this.m_item = new T[i];

    }

金沙注册送58 34

}

    泛型委托的自律:委托级别的自律只在宣称委托变量和实例化委托时利用,类似于在项目和办法的效率范围中进行的其他任何约束。

类的写法不变,只是引进了通用数据类型T就足以适用于其余数据类型,并且类型安全的。这么些类的调用方法:

泛型和反光

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

   
在Net二.0中间,扩张了反光以帮忙泛型参数。类型Type将来得以代表带有一定项指标实参(或绑定类型)或未内定类型的泛型(或称未绑定类型)。像C#壹.第11中学那样,您可以因而采取typeof运算符或通过调用每一种系列支持的GetType()来得到任何项指标Type。代码如下:

Stack

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

  a.Push(10);

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

  int x = a.Pop();

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

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

金沙注册送58 35

Stack

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

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

金沙注册送58 36

  b.Push("8888");

    typeof还能对未绑定的泛型实行操作,代码如下

string y = b.Pop();

金沙注册送58 37

其一类和object落成的类有完全差别的分别:

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

  1. 他是项目安全的。实例化了int类型的栈,就不能够处理string类型的数码,其余数据类型也1致。

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

  3. 无须类型转换。

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

泛型类实例化的论争
C#泛型类在编写翻译时,先生成人中学等代码IL,通用类型T只是四个占位符。在实例化类时,依照用户钦点的数据类型代替T并由即时编写翻译器(JIT)生开销地代码,这几个地面代码中早已选用了实际上的数据类型,等同于用实际类型写的类,所以分化的封闭类的本地代码是差异的。遵照那么些原理,大家得以那样认为:

金沙注册送58 38

泛型类的例外的封闭类是各自不相同的数据类型。

   
请留心”<>”的用法。要对包涵多少个类型参数的未绑定泛型类进行操作,请在”<>”中运用”,”

例:Stack

   
Type类中添加了新的措施和品质,用于提供关于该类型的泛型方面包车型客车反光音讯,见MSDN。

泛型类中数据类型的束缚
程序员在编辑泛型类时,总是会对通用数据类型T进行有意或无意地有假想,相当于说那个T一般的话是无法适应全部连串,但怎么着界定调用者传入的数据类型呢?那就需求对传播的数据类型进行约束,约束的方法是内定T的先人,即三番五次的接口或类。因为C#的单根继承性,所以约束能够有四个接口,但最七只可以有三个类,并且类必须在接口从前。这时就用到了C#2.0的新增关键字:

.net泛型约束  

所谓泛型,即因而参数化类型来兑未来相同份代码上操作多种数据类型。泛型编制程序是1种编程范式,它选取“参数化类型”将项目抽象化,从而达成更灵活的复用。

在概念泛型类时,能够对客户端代码能够在实例化类时用于项目参数的品各个类施加限制。借使客户端代码尝试接纳某些约束所不容许的档次来实例化类,则会生出编写翻译时不当。那么些限制称为约束。约束是应用
where 上下文关键字钦命的。

下表列出了伍体系型的自律:

约束 说明

T:struct

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

T:class

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

T:new()

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

T:<基类名>

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

T:<接口名称>

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

T:U

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

 —————————————

1.派生羁绊

1.常见的

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

二.约束放在类的实际派生之后

public
class B { }

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

3.足以继续二个基类和多少个接口,且基类在接口前面

public
class B { }

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

2.构造函数约束

1.常见的

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

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

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

三.值约束

1.常见的

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

二.与接口约束同时使用,在最前边(无法与基类约束,构造函数约束共同使用)

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>{ }

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

   
public class SubClass11 : B<int>
    { }

二.假使子类是泛型,而非具体的项目实参,则足以应用子类泛型参数作为泛型基类的钦赐项目

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

三.在子类重复基类的束缚(在行使子类泛型参数时,必须在子类级别重复在基类级别规定的别的自律)
    public class B<T> where T : ISomeInterface { }
    public class SubClass2<T> : B<T> where
T : ISomeInterface { }

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

七.泛型方法(C#贰.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.泛型方法的重载

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

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

//第二组重载
金沙注册送58 , 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 { }

//第5组重载

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;
        }
    }

四.泛型方法的覆写

(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 SubClass伍<T> : BaseClass四<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 obj二 = (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) { }
        }
    }

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#中数据类型有两大类:引用类型和值类型。引用类型如全数的类,值类型1般是言语的最中央项目,如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多少个数据,这么些类Stack二扩张了Stack的功力(当然也能够直接写在Stack中),他得以三回把多少个数据压入Stack中。当中Push是3个泛型方法,那一个办法的调用示例如下:

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#二.0中由于引入了泛型,导致静态成员变量的建制出现了某些变化:静态成员变量在相同封闭类间共享,分裂的封闭类间不共享。

那也卓殊不难精晓,因为分化的封闭类即使有相同的类名称,但鉴于各自传入了不相同的数据类型,他们是完全分歧的类,比如:

Stack

Stack

Stack

类实例a和b是平等档次,他们中间共享静态成员变量,但类实例c却是和a、b完全两样的类型,所以不能够和a、b共享静态成员变量。

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

泛型中的静态构造函数的规律和非泛型类是如出1辙的,只需把泛型中的不一样的封闭类领会为不一致的类即可。以下二种景况可激发静态的构造函数:

  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#的泛型是在实例的章程被调用时检查重载是不是产生模糊,而不是在泛型类本身编写翻译时检查。同时还得出3个关键尺度:

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

泛型类的章程重写
方法重写(override)的首要难题是格局签名的辨认规则,在这点上他与办法重载一样,请参见泛型类的办法重载。

泛型的利用限制
正文首固然在类中讲述泛型,实际上,泛型还足以用在类格局、接口、结构(struct)、委托等地方运用,使用方法差不多相同,就不再讲述。

小结
C#
泛型是开发工具库中的二个珍贵和稀有之宝。它们可以提升品质、类型安全和质量,缩短重复性的编制程序职责,简化总体编制程序模型,而这1切都以通过优雅的、可读性强的语法实现的。固然C# 泛型的基础是 C++ 模板,但 C#
通过提供编写翻译时安全和协助将泛型升高到了1个新水平。C#
利用了两阶段编译、元数据以及诸如约束和壹般方法之类的创新性的定义。毫无疑问,C#
的今后版本将三番五次发展泛型,以便添加新的功力,并且将泛型增加到诸如数码访问或本地化之类的其它

.NET Framework 领域。

在C#二.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泛型约束

所谓泛型,即通过参数化类型来促成在一如既往份代码上操作多种数据类型。泛型编制程序是1种编制程序范式,它使用“参数化类型”将品种抽象化,从而达成更灵活的复用。

在概念泛型类时,可以对客户端代码能够在实例化类时用于项目参数的门类连串施加限制。如若客户端代码尝试运用有个别约束所区别意的项目来实例化类,则会产生编写翻译时不当。这个限制称为约束。约束是运用
where 上下文关键字内定的。

下表列出了四种档次的牢笼:

自律表明:

T:struct

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

T:class

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

T:new()

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

T:<基类名>

类型参数必须是钦赐的基类或派生自钦赐的基类。

T:<接口名称>

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

T:U

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


一.派生封锁

1.常见的

public class MyClass5

二.束缚放在类的实在派生之后

public class B { }

public class MyClass6

叁.方可连续多个基类和八个接口,且基类在接口前边

public class B { }

public class MyClass7

2.构造函数约束

1.常见的

public class MyClass8

2.能够将构造函数约束和派生约束组合起来,前提是构造函数约束出现在约束列表的末段

public class MyClass8

三.值约束

1.常见的

public class MyClass9

2.与接口约束同时选取,在最前头(不能与基类约束,构造函数约束共同使用)

public class MyClass11

4.引用约束

1.常见的

public class MyClass10

伍.八个泛型参数

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

6.继承和泛型

public class B

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

    public class SubClass11 : B

2.壹旦子类是泛型,而非具体的种类实参,则足以选用子类泛型参数作为泛型基类的钦定项目

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

三.在子类重复基类的束缚(在运用子类泛型参数时,必须在子类级别重复在基类级别规定的别样自律)
public class B

4.构造函数约束
public class B

七.泛型方法(C#二.0泛型机制援助在”方法声名上带有类型参数”,这就是泛型方法)

一.泛型方法既能够涵盖在泛型类型中,又有什么不可涵盖在非泛型类型中

public class MyClass5
{

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

二.泛型方法的注脚与调用

public class MyClass5
{
public void MyMethod

3.泛型方法的重载

//第1组重载
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;
}
}

四.泛型方法的覆写

(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

10.编写翻译器允许你将泛型参数字呈现式强制转换来任何任何接口,但无法将其更换成类

class MyClass1

十一.接纳一时的 Object 变量,将泛型参数强制转换来其余任何类型

class MyClass2

十二.使用is和as运算符

public class MyClass3

相关文章

网站地图xml地图