首頁 後端開發 C#.Net教程 C#泛型程式設計

C#泛型程式設計

Dec 21, 2016 pm 02:47 PM

泛型:透過參數化類型來實現在同一份程式碼上操作多種資料型別。利用「參數化類型」將型別抽象化,從而實現靈活的複用。

範例程式碼:

class PRogram

    {

        static void        int obj = 2;

            Test test = new Test(obj);

            Console.WriteLine("int:" + test.obj);

            Test test1 = new Test(obj2);

            Console.WriteLine(" String:" + test1.obj);

            Console.Read();

      T>

    {

        public T obj;

        public Test(T obj)
        public Test(T obj)

        {

            this.obj = obj;

  
    int:2

String:hello world



程式分析:

1、  Test是一個泛型類。 T是要實例化的範式類型。如果T被實例化為int型,那麼成員變數obj就是int型的,如果T被實例化為string型,那麼obj就是string類型的。

2、  根據不同的類型,上面的程式顯示出不同的數值。



C#泛型機制:

C#泛型能力有CLR在運行時支援:C#泛型程式碼在編譯為IL程式碼和元資料時,採用特殊的佔位符來表示範式類型,並用專型有的IL指令支援泛型操作。而真正的泛型實例化工作以「on-demand」的方式,發生在JIT編譯時。



看看剛才的程式碼中Main函數的元資料

.method private hidebysig static void  Main(string[] args) cil managed
point
🠎     79 (0x4f)

  .maxstack  2

  .locals init ([0] int32 obj,

              [2] string obj2,

           [3] class CSharpStudy1.Test` 1 test1)

  IL_0000:  nop

  IL_0001:  ldc.i4.2

 

  IL_0004:  newobj     instance void class CSharpStudy1.Test`1 ::.ctor(!0)

  IL_0009:  stloc.1

  IL_000a:  ldstr        ldfld      !0 class CSharpStudy1.Test`1::obj

  IL_0015:  box        [mscorlib]System.Int32

  IL_001a:  call       string [mscorlib]System.String::Concat(object,

                                                              object)

  IL_001f:  call       void [mscorlib]System.Console::WriteLine(string )

  IL_0024:  nop

  IL_0025:  ldstr      "hello world"

IL_002a:  stloc.2

  IL_002b:  ldloc.2

  IL_002c:  newobj      stloc.3

  IL_0032:  ldstr      「字符串:"

  IL_0037:  ldloc.3

  IL_0038:  ldfld      !0    字串[mscorlib]System.String::Concat(string,

字串)

  IL_0042:  呼叫void [mscorlib]System.Console::WriteLine(string)

  IL_0047:  noppah ystem.Console::Read()

  IL_004d:  流行

IL_004e:  ret

} // 方法結束Program::Main



    接下來看看測試類別中建構函數的元資料

.method .ctor(!T obj) cil Managed

{

  // 代碼大小       17 (0x11)

  .maxstack  8
🎠 id [mscorlib]System.Object::.ctor()

  IL_0006:  不

  IL_0007 :  nop

  IL_0008:  ldarg.0

  IL_0009: ¢ SharpTest1.Test`1::obj

  IL_000f:  nop

  IL_0010:  ret

} / / end of method Test`1::.ctor



1、第一輪編譯時,編譯器只為Test型別產生「泛型版」的IL程式碼與元資料-並未進行泛型類型的實例化,T在中間只充當佔位符。例如:測試類型元資料中顯示的

2、JIT編譯時,當JIT編譯器第一次遇到Test時,將用int取代「範式版」IL程式碼與元數據中的T——進行泛型類型的實例化。例如:Main函數中顯示的

3、CLR為所有類型參數為“引用類型”的泛型類型產生相同的一個代碼;但是如果類型參數為“值類型”,對每一個不同的“值類型”,CLR將表示產生一個獨立的程式碼。因為實例化一個引用類型的泛型,它在記憶體中分配的大小是一樣的,但是當實例化一個值類型的時候,在記憶體中分配的大小是不一樣的。



C#泛型特點:

1、如果實例化泛型類型的參數相同,那麼JIT 編輯器就可以重複使用該類型,因此,C# 的泛化類型能夠避免了C++ 靜態模板可能導致程式碼膨脹的問題。

2、C# 泛化類型具有豐富的引用元數據,因此C#的泛型類型可以實現強大的引用技術。

3、C#的泛型類型採用“基類、接口、構造器,值類型/引用類型”的約束方式來實現對類型參數的引用“顯示約束”,提高了類型安全的同時,也失去了基於「簽章」的隱式約束所具有的高靈活性的C++模板



C#泛型繼承:

C#除了聲明可以另外泛型類型(包括類別與結構)外,也可以在基底類別中包含泛型類型的聲明。但基底類別如果是泛型類型,它的型別或以實例化,或是來自子類別(同樣是泛型型別)宣告的型別參數,看如下型別

class C

class D :C

class E:C

class F:C

類G:C // 非法

E型別為C型別提供了U、V,所以上面說的來自子類

F型別繼承於C,個人認為看成F繼承一個可以非泛型的類

G類型為非法的,因為G類型不是泛型,C是泛型,G無法提供C泛型的實例化



泛型類型的成員:

泛型類型的成員可以使用泛型類型宣告中的型別參數。但類型參數如果沒有任何約束,則只能在該類型上使用從System.Object繼承的公有成員。如下圖:




泛型介面:

泛型介面的型別參數不是實例化,或是來自實作類別宣告的型別參數



泛型委託:

泛型委託在回傳值和參數上都應用參數類型,這些參數類型同樣可以附帶合法的限制

delegate bool MyDelegate(T value);

class MyClass

{
 .}

    static bool G(string s){...}

    static void Main()

          MyDelegate p1 = new MyDelegate( F);

    }

}



泛型方法:

1、C#泛型機制只支援「在方法宣告上包含型別參數」-即泛型方法。

2、C#泛型機制不支援在方法以外的其他成員(包括屬性、事件、索引器、建構器、析構器)的宣告上包含型別參數,但這些成員本身可以包含在泛型類型中,並使用泛型類型的型別參數。

3、泛型方法既可以包含在泛型類型中,也可以包含在非泛型類型中。



泛型方法宣告:如下

public static int FunctionName(T value){...}



泛型方法的重載:




型法的重載:




型法的重載: );

public void Function1(U a);

這樣是不能構成泛型方法的重載。因為編譯器無法確定泛型類型T和U是否不同,也就無法確定這兩種方法是否不同



public void Function1(int x);

public void Function1(int x);

這樣可以構成重載



public void Function1(T t) where T:A;

public void Function1(T t) where T:B;

這樣不能構成泛型方法這樣不能構成泛型方法這樣不能構成泛型方法的重載。因為編譯器無法確定約束條件中的A和B是否不同,也就無法確定這兩個方法是否不同



泛型方法重寫:

在重寫的過程中,抽象類別中的抽象方法的約束是預設繼承的。如下:

abstract class Base

{

    public abstract T F(T t,U u) where U:T;

 );
}



class MyClass:Base

{

    public override X F(X x,Y y){...}
 . IComparable{}

}

對於MyClass中兩個重寫的方法來說

F方法是合法的,約束被默認繼承

G方法是非法的,指定任何約束都是多餘的


G方法是非法的,指定任何約束都是多餘的


泛型限制:

1、C#泛型要求對“所有泛型類型或泛型方法的類型參數”的任何假定,都要基於“顯式的約束”,以維護C#所要求的類型安全。

2、“顯式約束”由where子句表達,可以指定“基類約束”,“接口約束”,“構造器約束”,“值類型/引用類型約束”共四種約束。

3、“明確約束”並非必須,如果沒有指定“明確約束”,範式類型參數將只能存取System.Object類型中的公有方法。例如:在開始的例子中,定義的那個obj成員變數。例如我們在開始的例子中加入一個Test1類,在它當中定義兩個公共方法Func1、Func2,如下圖:






下面就開始分析這些限制:

基類約束:

下面就開始分析這些約束:

基類約束:

下面就開始分析這些限制class A

    {

        public void Func1()

       

    {

        public void Func2()

        , T>

        where S : A

        where T : B
 
        {

//S的變因可以呼叫Func1方法

            s.Func1();

             t.Func2();

        }

    }

介面限制:

interface IA

    {

        T Func1();

    }🎠        void Func2();

    }



    inter T Func3();

    }



    class MyClass

      , IC

    {

        public MyClass(T t, V v)

        {

            //T中的物件中使用Func1🠎   //T的物件           //V的物件可稱為Func2與Func3

            v );

        }

    }

構造器約束:

class A🎠   public A()

            { }

        }🠎 

            public B(int i )

            { }

        }

      {

            T t;

                          t = new T();

            }

        }



              public void Func()

            {
 
                C d = new C ();

            }

        }

  less. in the generic type or method C

    注意:C#現在只支援無參的構造器約束

    此時由於我們為B類型寫入了一個有參構造器,使得系統不會再為B自動創建一個無參的構造器,但是如果我們將B型別中加一個無參構造器,那麼物件d的實例化就不會報錯了。 B類型定義如下:

        class B

{

            public B()

                     { }

        }

值型/引用型別:

public struct A 🠎🜠值類型/引用型態:

public struct A 🠎

        public class C where T :      public class C where T :     C c1 = new C();

        C c2 = new C();

    c2物件在編譯時錯誤:The type 'B' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or methor 'C'


總結:

1、C#的泛型能力由CLR在運行時支持,它既不同於C++在編譯時所支援的靜態模板,也不同於java在編譯器層面使用「擦拭法」支援的簡單的泛型。

2、C#的泛型支援包括類別、結構、介面、委託四種泛型類型,以及方法成員。

3、C#的泛型採用“基類,接口,構造器,值類型/引用類型”的約束方式來實現對類型參數的“顯式約束”,它不支援C++模板那樣的基於簽名的隱式約束。

 以上就是C#泛型程式設計的內容,更多相關內容請關注PHP中文網(www.php.cn)! 



本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1666
14
CakePHP 教程
1426
52
Laravel 教程
1328
25
PHP教程
1273
29
C# 教程
1253
24
使用 C# 的活動目錄 使用 C# 的活動目錄 Sep 03, 2024 pm 03:33 PM

使用 C# 的 Active Directory 指南。在這裡,我們討論 Active Directory 在 C# 中的介紹和工作原理以及語法和範例。

C# 中的隨機數產生器 C# 中的隨機數產生器 Sep 03, 2024 pm 03:34 PM

C# 隨機數產生器指南。在這裡,我們討論隨機數產生器的工作原理、偽隨機數和安全數的概念。

C# 資料網格視圖 C# 資料網格視圖 Sep 03, 2024 pm 03:32 PM

C# 資料網格視圖指南。在這裡,我們討論如何從 SQL 資料庫或 Excel 檔案載入和匯出資料網格視圖的範例。

C# 中的階乘 C# 中的階乘 Sep 03, 2024 pm 03:34 PM

C# 階乘指南。這裡我們討論 C# 中階乘的介紹以及不同的範例和程式碼實作。

c#多線程和異步的區別 c#多線程和異步的區別 Apr 03, 2025 pm 02:57 PM

多線程和異步的區別在於,多線程同時執行多個線程,而異步在不阻塞當前線程的情況下執行操作。多線程用於計算密集型任務,而異步用於用戶交互操作。多線程的優勢是提高計算性能,異步的優勢是不阻塞 UI 線程。選擇多線程還是異步取決於任務性質:計算密集型任務使用多線程,與外部資源交互且需要保持 UI 響應的任務使用異步。

C# 中的模式 C# 中的模式 Sep 03, 2024 pm 03:33 PM

C# 模式指南。在這裡,我們討論 C# 中模式的介紹和前 3 種類型,以及其範例和程式碼實作。

C# 中的質數 C# 中的質數 Sep 03, 2024 pm 03:35 PM

C# 質數指南。這裡我們討論c#中素數的介紹和範例以及程式碼實作。

xml怎麼改格式 xml怎麼改格式 Apr 03, 2025 am 08:42 AM

可以採用多種方法修改 XML 格式:使用文本編輯器(如 Notepad )進行手工編輯;使用在線或桌面 XML 格式化工具(如 XMLbeautifier)進行自動格式化;使用 XML 轉換工具(如 XSLT)定義轉換規則;或者使用編程語言(如 Python)進行解析和操作。修改時需謹慎,並備份原始文件。

See all articles