威尼斯人线上娱乐

泛型约束实际选拔,泛型编程之泛型类

11 4月 , 2019  

前言

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

泛型编制程序是壹种编制程序范式,它采取“参数化类型”将品种抽象化,从而达成更为灵活的复用。在概念泛型类时,在对客户端代码能够在实例化类时,能够用项目参数的连串体系施加限制。在搭建底层框架时,是最普遍的编制程序方式。

 

来自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#二.0中,方法能够定义特定于其履行范围的泛型参数,如下所示:

一)、表示可透过索引访问的对象的强类型列表;提供用于对列表举办检索、排序和操作的措施。
二)、是ArrayList类的泛型等效类。
三)、可以运用二个平头索引访问此聚众中的成分;索引从零 初叶。
4)、尚可null空引用(VB中的Nothing)。
伍)、允许再度元素

泛型方法

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

 

  所谓泛型,即透过参数化类型来促成在平等份代码上操作多种数据类型。

威尼斯人线上娱乐 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 { }

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

public class B { }

public class MyClass6 : B where T : IComparable { }

3.可以一连1个基类和多少个接口,且基类在接口前边

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群

威尼斯人线上娱乐 2

 

作者:Jacky

来源:

宣称:本文版权归作者和乐乎共有,欢迎转发,但未经小编同意必须保留此段注明,且在篇章页面明显地方给出原著连接,不然保留追究法律权利的权利。

  泛型编制程序是1种编制程序范式,它接纳“参数化类型”将品种抽象化,从而达成更为灵活的复用。在概念泛型类时,在对客户端代码能够在实例化类时,可以用项目参数的类型种类施加限制。

    public class MyClass<T>
    {
        //钦赐MyMethod方法用以实施项目为X的参数
        public void MyMethod<X>(X x) 
        {
            //威尼斯人线上娱乐 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>() 
        {
            //威尼斯人线上娱乐 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);
    }
}

 

威尼斯人线上娱乐 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);
 }  

泛型委托的束缚

委托级其余牢笼只在宣称委托变量和实例化委托时利用,类似于在档次和格局的功力范围中推行的其余任何约束。

泛型和反光

在Net2.0个中,扩张了反光以协助泛型参数。类型Type今后得以象征带有一定项指标实参(或绑定类型)或未内定类型的泛型(或称未绑定类型)。像C#一.第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 上下文关键字钦命的。

威尼斯人线上娱乐 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) 
        {
            //威尼斯人线上娱乐 7
        }

Count
获取 List

 

        //此方法也认同钦命方法参数
        public void MyMethod<X>() 
        {
            //威尼斯人线上娱乐 8
        }
    }

四、List

派生约束

1.常见的

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

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

public
class B { }

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

叁.方可接二连三二个基类和多少个接口,且基类在接口前边

public
class B { }

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

威尼斯人线上娱乐 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 { }

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

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

2.比方子类是泛型,而非具体的品种实参,则足以行使子类泛型参数作为泛型基类的内定项目

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

3.在子类重复基类的自律(在应用子类泛型参数时,必须在子类级别重复在基类级别规定的其余自律)
    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(){
}

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

BinarySearch(Int32, Int32, T, IComparer

三、泛型方法

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

一.泛型方法既可以包含在泛型类型中,又足以分包在非泛型类型中

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

 

四.泛型方法的覆写

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

 

威尼斯人线上娱乐 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

6、 泛型参数字显示式强制转换

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

 

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

 

 

    public class MyClass
    {
        public T MyMethod<T>() 
        {
            //威尼斯人线上娱乐 11
        }
    }

CopyTo(T[])
将整个 List

七、 泛型参数强制转换来任何任何项目

行使权且的 Object 变量,将泛型参数强制转换来此外任何项目

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

 

威尼斯人线上娱乐 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

威尼斯人线上娱乐 13

FindIndex(Predicate

    public class MyClass
    {
        
        public void MyMethod<X>(X x) where X:IComparable<X>
        {
            //威尼斯人线上娱乐 14
        }
    }

ForEach
对 List

威尼斯人线上娱乐 15

GetEnumerator
再次回到循环访问 List

   
您不或然为类级其他泛型参数提供格局级别的束缚。类级别泛型参数的持有约束都必须在类功用范围中定义,代码如下所示

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

威尼斯人线上娱乐 16

Insert
将成分插入 List

    public class MyClass<T>
    {
        
        public void MyMethod<X>(X x,T t) where X:IComparable<X> where T:IComparer<T>
        {
            //威尼斯人线上娱乐 17
        }
    }

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

威尼斯人线上娱乐 18

LastIndexOf(T)
追寻钦定的靶子,并重回整个 List

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

Remove
从 List

威尼斯人线上娱乐 19

Reverse()
将整个 List

    public class MyClass<T> where T:IComparable<T>
    {
        
        public void MyMethod<X>(X x,T t) where X:IComparable<X> 
        {
            //威尼斯人线上娱乐 20
        }
    }

Sort()
应用暗中认可相比器对全体 List

威尼斯人线上娱乐 21

5、常用方法实例

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

(一)创制及开端化:
List

威尼斯人线上娱乐 22

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

    public class MyBaseClass
    {
        public virtual void SomeMethod<T>(T t)
        {
            //威尼斯人线上娱乐 23
        }
    }
    public class MyClass :MyBaseClass
    {
        public override void SomeMethod<X>(X x)
        {
            
        }
    }

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

威尼斯人线上娱乐 24

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

并且子类中的泛型方法不能够重新基类泛型方法的封锁,那或多或少和泛型类中的虚方法重写是有分别的,代码如下

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

威尼斯人线上娱乐 25

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

    public class MyBaseClass
    {
        public virtual void SomeMethod<T>(T t) where T:new()
        {
            //威尼斯人线上娱乐 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数据,也许别的自定义的数据类型,但我们一贯不主意,只可以分别写四个点子处理种种数据类型,因为方法的参数类型分化。有未有1种情势,在格局中传播通用的数据类型,那样不就能够统一代码了呢?泛型的产出正是特地化解那些难点的。读完本篇文章,你会对泛型有越来越深的掌握。
为何要利用泛型
为了领会那一个题目,我们先看上面的代码,代码省略了某个剧情,但意义是贯彻二个栈,这一个栈只好处理int数据类型:

威尼斯人线上娱乐 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];

    }

威尼斯人线上娱乐 28

}

    public class MyBaseClass
    {
        public virtual void SomeMethod<T>(T t) where T:new()
        {
            //威尼斯人线上娱乐 29
        }
    }
    public class MyClass :MyBaseClass
    {
        //正确写法
        public override void SomeMethod<X>(X x)
        {
            base.SomeMethod<X>(x);
            base.SomeMethod(x);
        }
    }

地点代码运转的很好,然而,当大家要求贰个栈来保存string类型时,该如何做呢?很多人都会想到把地点的代码复制一份,把int改成string不就行了。当然,那样做自小编是一向不别的难点的,但一个特出的主次是不会那样做的,因为她想到若从此再需求long、Node类型的栈该怎么样做呢?还要再复制吗?杰出的程序员会想到用3个通用的数据类型object来促成那些栈:

威尼斯人线上娱乐 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];

    }



}

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

其一栈写的不错,他非常灵活,可以选择任何数据类型,能够说是一劳永逸。但完美地讲,也不是绝非缺陷的,首要呈今后:

威尼斯人线上娱乐 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();

威尼斯人线上娱乐 32

地方的代码在编写翻译时是截然没难点的,但鉴于Push了三个Node1类型的多少,但在Pop时却须求变换为Node2类型,那将面世程序运维时的类型转换格外,但却逃离了编写翻译器的自笔者批评。

    委托推理:C#二.0使你能够将艺术引用的一向分配转变为委托变量。将上边的代码改造如下

本着object类型栈的题材,大家引进泛型,他得以优雅地消除这一个标题。泛型用用三个经过的数据类型T来代替object,在类实例化时钦赐T的项目,运维时(Runtime)自动编写翻译为本地代码,运营成效和代码质量都有相当大拉长,并且有限协理数据类型安全。

威尼斯人线上娱乐 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];

    }

威尼斯人线上娱乐 34

}

    泛型委托的封锁:委托级其余自律只在评释委托变量和实例化委托时行使,类似于在类型和方法的成效范围中实施的另外任何约束。

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

泛型和反光

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

   
在Net二.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类型的类

威尼斯人线上娱乐 35

Stack

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

b.Push(拾); //那1行编译不通过,因为类b只收取string类型的数码

威尼斯人线上娱乐 36

  b.Push("8888");

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

string y = b.Pop();

威尼斯人线上娱乐 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)生开支地代码,这么些本地代码中早就接纳了实际的数据类型,等同于用实际类型写的类,所以不一致的封闭类的本地代码是不均等的。依据这一个原理,大家能够这么认为:

威尼斯人线上娱乐 38

泛型类的分歧的封闭类是分别分歧的数据类型。

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

例:Stack

   
Type类中添加了新的办法和性质,用于提供有关该类型的泛型方面包车型大巴反射新闻,见MSDN。

泛型类中数据类型的牢笼
程序员在编写制定泛型类时,总是会对通用数据类型T举办有意或无意地有假想,也正是说这些T一般的话是不能够适应全数类型,但什么界定调用者传入的数据类型呢?这就必要对传播的数据类型实行封锁,约束的章程是内定T的先世,即持续的接口或类。因为C#的单根继承性,所以约束能够有八个接口,但最八只可以有2个类,并且类必须在接口在此以前。这时就用到了C#二.0的新增关键字:

.net泛型约束  

所谓泛型,即通过参数化类型来贯彻在同样份代码上操作两种数据类型。泛型编制程序是一种编制程序范式,它采纳“参数化类型”将品种抽象化,从而实现更灵活的复用。

在概念泛型类时,能够对客户端代码能够在实例化类时用于项目参数的花色体系施加限制。假若客户端代码尝试采纳有个别约束所不允许的体系来实例化类,则会生出编写翻译时不当。那一个限制称为约束。约束是使用
where 上下文关键字内定的。

下表列出了5连串型的约束:

约束 说明

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

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

4.引用约束

1.常见的

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

5.多少个泛型参数

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

3.在子类重复基类的羁绊(在采用子类泛型参数时,必须在子类级别重复在基类级别规定的其余约束)
    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(){
}

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

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

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

//第2组重载
 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 SubClass四 : BaseClass肆<int> //使用实参继承的时候方法要运用实参的类型
    {
        public override int SomeMethod()
        {
            return 0;
        }
    }

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

9.编写翻译器只同意将泛型参数隐式强制转换来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;           //不能够透过编译
        }
    }

 

拾1.选取一时的
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);

        }

    }

}

本来的类Stack2回只可以Push多少个数据,这么些类Stack二扩大了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#二.0中由于引入了泛型,导致静态成员变量的建制出现了部分变动:静态成员变量在平等封闭类间共享,分歧的封闭类间不共享。

那也分外不难通晓,因为分歧的封闭类尽管有平等的类名称,但由于个别传入了区别的数据类型,他们是一点一滴两样的类,比如:

Stack

Stack

Stack

类实例a和b是千篇1律类型,他们之间共享静态成员变量,但类实例c却是和a、b完全两样的品类,所以无法和a、b共享静态成员变量。

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

泛型中的静态构造函数的法则和非泛型类是如出一辙的,只需把泛型中的分裂的封闭类领会为区别的类即可。以下三种境况可激发静态的构造函数:

  1. 一定的封闭类第3回被实例化。

  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具有同样的签署,但却能调用成功,因为她先期相配了第4个add。但假设剔除了第多少个add,下边包车型大巴调用代码则无法编译通过,提醒方法发生的歪曲,因为运营时惊慌失措在第一个add和第三个add之间接选举拔。

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

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

那两行调用代码可科学编写翻译,因为传播的string和int,使三个add具有分歧的签订契约,当然能找到唯壹相配的add方法。

由上述示例可见,C#的泛型是在实例的方法被调用时检查重载是或不是产生模糊,而不是在泛型类本人编译时检查。同时还得出一个主要尺度:

当1般方法与泛型方法具有相同的签名时,会覆盖泛型方法。

泛型类的不二秘诀重写
格局重写(override)的显要难题是措施签名的鉴定分别规则,在那或多或少上他与艺术重载壹样,请参见泛型类的点子重载。

泛型的施用限制
正文首借使在类中讲述泛型,实际上,泛型还是能用在类情势、接口、结构(struct)、委托等方面使用,使用办法差不离相同,就不再讲述。

小结
C#
泛型是支付工具库中的一个珍贵和稀有之宝。它们得以增加质量、类型安全和质量,缩小重复性的编制程序职责,简化总体编制程序模型,而那一切都以通过优雅的、可读性强的语法完毕的。就算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泛型约束

所谓泛型,即透过参数化类型来兑今后壹如既往份代码上操作各个数据类型。泛型编制程序是一种编制程序范式,它利用“参数化类型”将品种抽象化,从而完成更为灵活的复用。

在概念泛型类时,能够对客户端代码能够在实例化类时用于项目参数的档次种类施加限制。假设客户端代码尝试利用某些约束所不容许的连串来实例化类,则会发出编写翻译时不当。那些限制称为约束。约束是行使
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

二.构造函数约束

1.常见的

public class MyClass8

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

public class MyClass8

三.值约束

1.常见的

public class MyClass9

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

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

二.假使子类是泛型,而非具体的花色实参,则足以采取子类泛型参数作为泛型基类的钦命项目

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

三.在子类重复基类的牢笼(在采纳子类泛型参数时,必须在子类级别重复在基类级别规定的任何自律)
public class B

肆.构造函数约束
public class B

七.泛型方法(C#二.0泛型机制辅助在”方法声名上含蓄类型参数”,这便是泛型方法)

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

public class MyClass5
{

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

贰.泛型方法的评释与调用

public class MyClass5
{
public void MyMethod

3.泛型方法的重载

//第三组重载
void MyMethod1

void MyMethod1(U u, int i){ }

//第三组重载
void MyMethod2

//第2组重载,若是有五个泛型参数
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

8.虚拟方法

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

101.选拔权且的 Object 变量,将泛型参数强制转换成别的任何项目

class MyClass2

十二.使用is和as运算符

public class MyClass3


相关文章

发表评论

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

网站地图xml地图