泛型约束,泛型计算

By admin in 4858.com on 2019年3月27日

前言

所谓泛型,即透过参数化类型来贯彻在相同份代码上操作多样数据类型。

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

 

来自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中,方法可以定义特定于其实施范围的泛型参数,如下所示:

1)、表示可经过索引访问的靶子的强类型列表;提供用于对列表举行检索、排序和操作的方法。
2)、是ArrayList类的泛型等效类。
3)、能够使用一个平头索引访问此聚众中的元素;索引从零 开始。
4)、能够收起null空引用(VB中的Nothing)。
5)、允许再度成分

泛型方法

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

 

  所谓泛型,即透过参数化类型来落到实处在相同份代码上操作种种数据类型。

4858.com 1

二、List

.NET泛型约束

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

下表列出了各样档次的束缚:

 

约束 说明

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

3.能够一而再二个基类和多少个接口,且基类在接口前面

public class B { }

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

 

构造函数约束

1.常见的

public class MyClass8 where T : new() { }

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

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

 

值约束

1.常见的

public class MyClass9 where T : struct { }

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

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群

4858.com 2

 

作者:Jacky

来源:

声称:本文版权归笔者和博客园共有,欢迎转发,但未经小编同意必须保留此段注脚,且在文章页面显明地点给出原版的书文连接,不然保留追究法律义务的职务。

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

    public class MyClass<T>
    {
        //内定MyMethod方法用以实施项目为X的参数
        public void MyMethod<X>(X x) 
        {
            //4858.com 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>() 
        {
            //4858.com 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);
    }
}

 

4858.com 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#2.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);
 }  

泛型委托的封锁

委托级其余束缚只在声明委托变量和实例化委托时行使,类似于在品种和章程的功效范围中执行的别样任何自律。

泛型和反光

在Net2.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 上下文关键字钦命的。

4858.com 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) 
        {
            //4858.com 7
        }

Count
获取 List

 

        //此方法也同意内定方法参数
        public void MyMethod<X>() 
        {
            //4858.com 8
        }
    }

四、List

派生约束

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

4858.com 9

Add
将目的添加到 List

构造函数约束

1.常见的

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

2.得以将构造函数约束和派生约束组合起来,前提是构造函数约束出今后约束列表的尾声

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

    注意:属性和索引器无法内定本人的泛型参数,它们只好使用所属类中定义的泛型参数进行操作。

AddRange
将钦点集合的元素添加到 List

值约束

1.常见的

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

2.与接口约束同时选择,在最前方(不能够与基类约束,构造函数约束共同利用)

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

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

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

BinarySearch(Int32, Int32, T, IComparer

叁 、泛型方法

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

    注意:泛型方法不可能只依据再次回到值的项目估计出类型,代码如下:

Clear
从 List

四 、虚拟方法

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

 

4858.com 10

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

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

编写翻译器只允许将泛型参数隐式强制转换成 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>() 
        {
            //4858.com 11
        }
    }

CopyTo(T[])
将整个 List

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

使用一时半刻的 Object 变量,将泛型参数强制转换成其它任何类型

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

 

4858.com 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

4858.com 13

FindIndex(Predicate

    public class MyClass
    {
        
        public void MyMethod<X>(X x) where X:IComparable<X>
        {
            //4858.com 14
        }
    }

ForEach
对 List

4858.com 15

GetEnumerator
重返循环访问 List

   
您不大概为类级其余泛型参数提供格局级其他约束。类级别泛型参数的持有约束都不能不在类功效范围中定义,代码如下所示

IndexOf(T)
探寻内定的目的,并回到整个 List

4858.com 16

Insert
将成分插入 List

    public class MyClass<T>
    {
        
        public void MyMethod<X>(X x,T t) where X:IComparable<X> where T:IComparer<T>
        {
            //4858.com 17
        }
    }

InsertRange
将集聚中的有个别成分插入 List

4858.com 18

LastIndexOf(T)
搜寻钦定的指标,并回到整个 List

而上边包车型大巴代码是不错的

Remove
从 List

4858.com 19

Reverse()
将整个 List

    public class MyClass<T> where T:IComparable<T>
    {
        
        public void MyMethod<X>(X x,T t) where X:IComparable<X> 
        {
            //4858.com 20
        }
    }

Sort()
行使默许相比较器对全部 List

4858.com 21

5、常用方法实例

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

(1)成立及初步化:
List

4858.com 22

(2)添加3个要素 List.Add(T item)
mlist.Add(“d”);

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

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

4858.com 24

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

还要子类中的泛型方法不可能再度基类泛型方法的封锁,这点和泛型类中的虚方法重写是有分其余,代码如下

(5)遍历List中元素
foreach(T element in mlist)
T的档次与mlist声明时一律{  Console.WriteLine(element);}

4858.com 25

(6)删除成分
List.Remove(T item)
剔除一个值mlist.Remove(“a”);

    public class MyBaseClass
    {
        public virtual void SomeMethod<T>(T t) where T:new()
        {
            //4858.com 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数据类型:

4858.com 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];

    }

4858.com 28

}

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

地点代码运营的很好,但是,当大家需求1个栈来保存string类型时,该如何是好吧?很多个人都会想到把上面的代码复制一份,把int改成string不就行了。当然,那样做作者是从未别的难题的,但一个卓越的次第是不会这么做的,因为他想到若从此再必要long、Node类型的栈该如何做啊?还要再复制吗?卓绝的程序员会想到用三个通用的数据类型object来兑现那个栈:

4858.com 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];

    }



}

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

本条栈写的正确,他很是灵活,能够接到任何数据类型,能够说是一劳永逸。但完美地讲,也不是尚未缺陷的,重要呈以往:

4858.com 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();

4858.com 32

下面包车型地铁代码在编写翻译时是一心没难题的,但由于Push了三个Node1类型的多少,但在Pop时却供给改换为Node2类型,那将现出程序运维时的类型转换极度,但却逃离了编写翻译器的反省。

    委托推理:C#2.0使你能够将艺术引用的一贯分配转变为委托变量。将地点的代码改造如下

针对object类型栈的标题,大家引入泛型,他得以优雅地缓解这个难题。泛型用用三个通过的数据类型T来代替object,在类实例化时钦点T的类型,运营时(Runtime)自动编写翻译为地面代码,运营功能和代码质量都有不小增加,并且保险数据类型安全。

4858.com 33

选取泛型
上面是用泛型来重写上边包车型客车栈,用二个通用的数额类型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];

    }

4858.com 34

}

    泛型委托的牢笼:委托级其他封锁只在宣称委托变量和实例化委托时行使,类似于在项目和方法的效率范围中举办的其它任何自律。

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

泛型和反光

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

   
在Net2.0中路,扩展了反光以支撑泛型参数。类型Type以往能够象征带有一定项指标实参(或绑定类型)或未钦定类型的泛型(或称未绑定类型)。像C#1.第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类型的类

4858.com 35

Stack

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

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

4858.com 36

  b.Push("8888");

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

string y = b.Pop();

4858.com 37

其一类和object达成的类有完全不一样的分别:

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

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

  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)生开销地代码,这几个地方代码中早就运用了实际上的数据类型,等同于用实际类型写的类,所以分化的封闭类的本地代码是不等同的。依照这么些原理,我们得以这么认为:

4858.com 38

泛型类的不一致的封闭类是各自分化的数据类型。

   
请小心”<>”的用法。要对含蓄七个档次参数的未绑定泛型类举办操作,请在”<>”中应用”,”

例:Stack

   
Type类中添加了新的法子和属性,用于提供有关该品种的泛型方面包车型客车反射音讯,见MSDN。

泛型类中数据类型的牢笼
程序员在编写泛型类时,总是会对通用数据类型T举行有意或无意地有假想,相当于说那些T一般的话是不可能适应全数项目,但哪些界定调用者传入的数据类型呢?那就需求对传播的数据类型举办约束,约束的主意是钦定T的祖先,即持续的接口或类。因为C#的单根继承性,所以约束能够有多少个接口,但最八只可以有三个类,并且类必须在接口在此以前。这时就用到了C#2.0的新增关键字:

.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.足以继续2个基类和两个接口,且基类在接口后面

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

4858.com ,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){ }

//第1组重载,就算有四个泛型参数
 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;
        }
    }

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

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必须有1个无参构造函数,不然编写翻译失利。

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

        }

    }

}

本来的类Stack3次只可以Push3个数量,那几个类Stack2扩大了Stack的功力(当然也足以直接写在Stack中),他得以一次把七个数据压入Stack中。个中Push是1个泛型方法,这些点子的调用示例如下:

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

Stack

Stack

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

泛型中的静态构造函数
静态构造函数的规则:只好有2个,且不能够有参数,他只可以被.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 领域。

在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.方可持续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

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有