天天看點

淺談C#泛型的定義、繼承、方法和限制

摘要:本文介紹了如何定義一個C#泛型類,以及實作泛型類的繼承、方法和限制。

      C#泛型參數化了類型,把類型作為參數抽象出來,進而使我們在實際的運用當中能夠更好的實作代碼的重複利用,同時它提供了更強的類型安全,更高的效率,不過在限制方面,它隻支援顯示的限制,這樣在靈活性方面就顯得不是那麼好了。我覺得它之是以能夠提供更高的效率是因為泛型在執行個體化的時候采用了"on-demand"的模式,即按需執行個體化,發生在JIT(Just In Time)編譯時。

     下面來看如何定義一個C#泛型類,很簡單,你隻需要意識到一點,在這裡,類型已經被參數化了:

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

namespace GenericTest
{
    class Program
    {
        static void Main(string[] args)
        {
            //使用string,int來執行個體化Test< T,S>類  
            Test<string, int> t = new Test<string, int>("SHY520", 22);

            //調用泛型類中的方法  
            t.SetValue();
        }
    }

    /**/
    /// < summary>  
    /// 定義一個泛型類,該類有兩個類型參數,分别是T,S  
    /// http://www.cnblogs.com/jara 
    /// < /summary>  
    /// < typeparam name="T">類型參數< /typeparam>  
    /// < typeparam name="S">類型參數< /typeparam>  
    public class Test<T, S>
    {
        //泛型類的類型參數可用于類成員  
        private T name;
        private S age;

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

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

     上面的例子不是很恰當,目的是讓初學泛型的你了解一下泛型的定義及執行個體化方法,如上,我們定義了一個泛型類,那麼如何實作C#泛型類的繼承呢?這裡需要滿足下面兩點中的任何一點即可:

    1、泛型類繼承中,父類的類型參數已被執行個體化,這種情況下子類不一定必須是泛型類;

    2、父類的類型參數沒有被執行個體化,但來源于子類,也就是說父類和子類都是泛型類,并且二者有相同的類型參數;

//如果這樣寫的話,顯然會報找不到類型T,S的錯誤  
public class TestChild : Test< T, S> { }  
 
//正确的寫法應該是  
public class TestChild : Test< string, int>{ }  
public class TestChild< T, S> : Test< T, S> { }  
public class TestChild< T, S> : Test< String, int> { }       

 接着我們來看看泛型接口,其建立以及繼承規則和上面說的泛型類是一樣的,看下面的代碼:

public interface IList<T>
{
    T[] GetElements();
}
public interface IDictionary<K, V>
{
    void Add(K key, V value);
}

// 泛型接口的類型參數要麼已執行個體化  
// 要麼來源于實作類聲明的類型參數  
class List<T> : IList<T>, IDictionary<int, T>
{
    public T[] GetElements() { return null; }
    public void Add(int index, T value)
    { }
}      

在來看一下C#泛型委托,首先我們定義一個類型參數為T的委托,然後在類中利用委托調用方法:

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

namespace GenericTest
{
    //定義一個委托,類型參數為T,傳回值類型T  
    //泛型委托支援在傳回值和參數上應用類型參數  
    delegate string GenericDelete<T>(T value);

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

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

     我們再來看C#泛型方法,C#的泛型機制隻支援在方法申明上包含類型參數,也即是泛型方法。特别注意的是,泛型不支援在除了方法以外的其他類/接口成員上使用類型參數,但這些成員可以被包含在泛型類型中,并且可以使用泛型類型的類型參數。還有一點需要說的就是,泛型方法可以在泛型類型中,也可以存在于非泛型類型中。下面我們分别看一下泛型類型的申明,調用,重載和覆寫。

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

namespace GenericTest
{
    class GenericClass
    {
        //申明一個泛型方法  
        public T getvalue<T>(T t)
        {
            return t;
        }

        //調用泛型方法  
        //注意:在調用泛型方法時,對泛型方法的類型參數執行個體化  
        public int useMethod()
        {
            return this.getvalue<int>(10);
        }

        //重載getvalue方法  
        public int getvalue(int i)
        {
            return i;
        }
    }

    //下面示範覆寫  
    //要注意的是,泛型方法被覆寫時,限制被預設繼承,不需要重新指定限制關系  
    abstract class Parent
    {
        public abstract K TEST<K, V>(K k, V v) where K : V;
    }

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

     最後我們來看一下C#泛型中的限制:

     C#中的泛型隻支援顯示的限制,因為這樣才能保證C#所要求的類型安全,但顯示的限制并非時必須的,如果不加限制,泛型類型參數将隻能通路System.Object類型中的公有方法。“顯式限制”由where子句表達,可以指定“基類限制”,“接口限制”,“構造器限制”,“值類型/引用類型限制”共四種限制。下面的例子來源于李建忠老師的講座PPT。

1、基類限制:

class A { public void F1() {} }   
class B { public void F2() {} }   
class C< S,T>   
where S: A // S繼承自A   
where T: B // T繼承自B   
{   
 // 可以在類型為S的變量上調用F1,  
 // 可以在類型為T的變量上調用F2   
}        

2、接口限制

interface IPrintable { void Print(); }  
interface IComparable< T> { int CompareTo(T v);}  
interface IKeyProvider< T> { T GetKey(); }  
class Dictionary< K,V>   
where K: IComparable< K>   
where V: IPrintable, IKeyProvider< K>   
{   
 // 可以在類型為K的變量上調用CompareTo,   
 // 可以在類型為V的變量上調用Print和GetKey   
}       

3、構造器限制

class A { public A() { } }   
class B { public B(int i) { } }   
class C< T>   
where T : new()   
{   
 //可以在其中使用T t=new T();   
}   
C< A> c=new C< A>(); //可以,A有無參構造器  
C< B> c=new C< B>(); //錯誤,B沒有無參構造器       

4、值/引用類型限制

public struct A { }   
public class B { }   
class C< T>   
where T : struct   
{   
 // T在這裡面是一個值類型   
}   
C< A> c=new C< A>(); //可以,A是一個值類型  
C< B> c=new C< B>(); //錯誤,B是一個引用類型      

轉載于:https://www.cnblogs.com/jara/p/3458583.html

c#