1. 程式人生 > >C#泛型特性總結

C#泛型特性總結

宣告,用泛型型別T:
public class List<T>
{
}

public delegate void Display<T>(T value)
{}
對泛型有更進一步的限定,必須實現一個介面或派生自父類,或者使用了特定的泛型型別,或者使用了多個泛型型別,例如:
public delegate void EventHandle<TEventArgs>(object sender, TEventArgs e)
{}
public delegate TOutput Convert<TInput, TOutput>(TInput from)
{}
public class SortedList<TKey, TValue>
{}

2.C#範型優點 1). 去掉裝箱拆箱,效能更高更安全:例項化時候相比非範型的資料結構用引用型別有效能上面的優勢,不需要裝箱放入和拆箱強轉的效能損耗,且訪問時候型別安全。預設的資料結構是儲存引入的,值型別傳入時候就要裝箱,值型別獲取時候要強轉就要拆箱,不斷的裝箱拆箱是很影響效能的。 2).泛型可以多語言相互呼叫: 和其它類型範型因為是CRL例項化的,所以一種語言定義範型類介面方法其它語言可以使用。 3). 共享引用型別泛型,更小程式碼:範型型別例項化時候引用只例項化一份範型程式碼,值型別例項化不同值類型範型程式碼。
3.使用泛型需要注意的事項 範型中注意要用default返回預設值。
範型約束where可以約束指定泛型型別是某種類或某種結構體,只能指定預設建構函式的約束不能指定其它形式的建構函式的約束,介面不能指定操作符過載。 where T:struct T是值型別 where T:class T是引用型別 where T:IFoo T必須實現介面 where T:Foo T必須繼承類 where T:new() T必須有預設建構函式 where T1:T2 多個泛型,T1必須繼承T2 範型介面,介面中可以使用範型限定,介面中的方法引數可以用範型型別,.net庫中就要很多範型介面。
4.泛型約束例項 // 1.C#自動生成屬性欄位 // 2.泛型管理器,有where 實現介面約束 // 3.lock (this) 在private/private static 中更加安全。 // 4.foreach語句的表達形式
namespace Wrox.ProCSharp.Generics
{
    public interface IDocument
    {
        string Title { get; set; }
        string Content { get; set; }
    }

    public class Document : IDocument
    {
        // C#3.0以後會自動生成屬性欄位由CRL生成,例如.field private string '<Name>k__BackingField'
        // 需要同時提供預設的get;set;訪問器,實際開發中很多應用,簡化程式碼。
        public Document()
        {
        }
        public Document(string title, string content)
        {
            this.Title = title;
            this.Content = content;
        }

        public string Title { get; set; }
        public string Content { get; set; }
    }
}

using System;
using System.Collections.Generic;
namespace Wrox.ProCSharp.Generics
{
    // 泛型管理器,有where 實現介面約束
    public class DocumentManager<TDocument>
        where TDocument : IDocument
    {
        private readonly Queue<TDocument> documentQueue = new Queue<TDocument>();
        public void AddDocument(TDocument doc)
        {
            // 進入臨界區
            lock (this)
            {
                documentQueue.Enqueue(doc);
            }// 離開臨界區
        }

        // 只讀屬性
        public bool IsDocumentAvailable
        {
            get { return documentQueue.Count > 0; }
        }

        public void DisplayAllDocuments()
        {
            // foreach語句的表達形式
            foreach (TDocument doc in documentQueue)
            {
                Console.WriteLine(doc.Title);
            }
        }

        public TDocument GetDocument()
        {
            // default將對值型別賦予預設值,引用型別賦予null
            TDocument doc = default(TDocument);
            // 1.lock 關鍵字可確保當一個執行緒位於程式碼的臨界區時,另一個執行緒不會進入該臨界區。
            // 如果其他執行緒嘗試進入鎖定的程式碼,則它將一直等待(即被阻止),直到該物件被釋放。
            // lock 關鍵字在塊的開始處呼叫 Enter,而在塊的結尾處呼叫 Exit。
           
            // 2.通常,應避免鎖定 public 型別,否則例項將超出程式碼的控制範圍。
            // 最佳做法是定義 private 物件來鎖定, 或 private static 物件變數來保護所有例項所共有的資料
            lock (this)
            {
                doc = documentQueue.Dequeue();
            }
            return doc;
        }
    }
}

using System;
namespace Wrox.ProCSharp.Generics
{
    class Program
    {
        static void Main()
        {
            var dm = new DocumentManager<Document>();
            dm.AddDocument(new Document("Title A", "Sample A"));
            dm.AddDocument(new Document("Title B", "Sample B"));
            dm.DisplayAllDocuments();
            if (dm.IsDocumentAvailable)
            {
                Document d = dm.GetDocument();
                Console.WriteLine(d.Content);
            }
        }
    }
}

5.泛型容器優點和支援迭代器訪問的容器的實現,yield 語句的使用

using System.Collections;
using System.Collections.Generic;
namespace Wrox.ProCSharp.Generics
{
    public class LinkedList<T> : IEnumerable<T>
    {
        public LinkedListNode<T> First { get; private set; }
        public LinkedListNode<T> Last { get; private set; }

        public LinkedListNode<T> AddLast(T node)
        {
            var newNode = new LinkedListNode<T>(node);
            if (First == null)
            {
                First = newNode;
                Last = First;
            }
            else
            {
                Last.Next = newNode;
                Last = newNode;
            }
            return newNode;
        }

        // 實現IEnumerable的獲取真正迭代器的方法就可以了,真正迭代MoveNext交給IEnumerator<T>去處理
        public IEnumerator<T> GetEnumerator()
        {
            LinkedListNode<T> current = First;

            while (current != null)
            {
                yield return current.Value;
                current = current.Next;
            }
        }

        // 需要重寫的IEnumerable.GetEnumerator方法
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
}

using System;
namespace Wrox.ProCSharp.Generics
{
    class Program
    {
        static void Main()
        {
            // int型別,使用泛型的連結串列比Object型別的連結串列效能好,編譯就可以發現錯誤
            var list2 = new LinkedList<int>();
            list2.AddLast(1);
            list2.AddLast(3);
            list2.AddLast(5);

            // 呼叫端實現迭代,輸出元素
            foreach (int i in list2)
            {
                Console.WriteLine(i);
            }

            // string型別,使用泛型的連結串列比Object型別的連結串列效能好,編譯就可以發現錯誤
            var list3 = new LinkedList<string>();
            list3.AddLast("2");
            list3.AddLast("four");
            list3.AddLast("foo");

            foreach (string s in list3)
            {
                Console.WriteLine(s);
            }

        }
    }
}

6.泛型方法和多種委託的實現 泛型方法可以有where約束,委託可以用泛型的等。 泛型方法可以被過載和具有多型性,泛型是在編譯期間決定的使用了型別,所以在執行期間是不會再調整呼叫的多型泛型函式的。
using System;
namespace Wrox.ProCSharp.Generics
{
    public interface IAccount
    {
        decimal Balance { get; }
        string Name { get; }
    }

    public class Account : IAccount
    {
        public string Name { get; private set; }
        public decimal Balance { get; private set; }

        public Account(string name, Decimal balance)
        {
            this.Name = name;
            this.Balance = balance;
        }
    }
}


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

namespace Wrox.ProCSharp.Generics
{
    public static class Algorithm
    {
        public static decimal AccumulateSimple(IEnumerable<Account> source)
        {
            decimal sum = 0;
            foreach (Account a in source)
            {
                sum += a.Balance;
            }
            return sum;
        }

        public static decimal Accumulate<TAccount>(IEnumerable<TAccount> source)
            where TAccount : IAccount
        {
            decimal sum = 0;

            foreach (TAccount a in source)
            {
                sum += a.Balance;
            }
            return sum;
        }

        public static T2 Accumulate<T1, T2>(IEnumerable<T1> source, Func<T1, T2, T2> action)
        {
            T2 sum = default(T2);
            foreach (T1 item in source)
            {
                // Func<T1, T2, T2>委託,應該是前面T1,T2是函式引數,後面引數T2是返回值
                sum = action(item, sum);
            }
            return sum;
        }
    }
}

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

namespace Wrox.ProCSharp.Generics
{
    class Program
    {
        static void Main()
        {
            // 直接用容器的建構函式為容器增加元素
            var accounts = new List<Account>()
            {
                new Account("Christian", 1500),
                new Account("Stephanie", 2200),
                new Account("Angela", 1800)
            };

            // 基礎資料結構型別,可以直接賦值給指定型別的IEnumerable<Account>型別
            decimal amount = Algorithm.AccumulateSimple(accounts);
            Console.WriteLine("after Algorithm.AccumulateSimple: " + amount);

            amount = Algorithm.Accumulate(accounts);
            Console.WriteLine("after Algorithm.Accumulate: " + amount);
            // 委託(item, sum) => sum += item.Balance,前面應該item和sum都是類似#define的巨集定義,=>後面是返回值
            amount = Algorithm.Accumulate<Account, decimal>(accounts, (item2, sum2) => sum2 += item2.Balance);
            Console.WriteLine("after Algorithm.Accumulate<Account, decimal>: " + amount);
        }
    }
}

using System;
namespace Wrox.ProCSharp.Generics
{

    public class MethodOverloads
    {
        public void Foo<T>(T obj)
        {
            Console.WriteLine("Foo<T>(T obj), obj type: {0}", obj.GetType().Name);
        }

        public void Foo(int x)
        {
            Console.WriteLine("Foo(int x)");
        }

        public void Bar<T>(T obj)
        {
            Foo(obj);
        }
    }

    class Program
    {
        static void Main()
        {
            var test = new MethodOverloads();
            // 用Foo(int x)
            test.Foo(33);
            // 用Foo<T>(T obj)
            test.Foo("abc");
            // 編譯期間決定的,所以是用Foo<T>(T obj)
            test.Bar(44);
        }
    }
}

7.泛型的協變和抗變 C#4.0引入的泛型變體的概念,就是泛型的型別是可變的。 協變要求實現的泛型的型別是子類,要變到沒有實現泛型型別的父類,是很協調理所當然的。 抗變(逆變)要求實現泛型的型別是父類,要變到沒有實現泛型型別的子類,是一種有點逆向的轉換。這個 1)4.0之前泛型型別介面是不變的也即是泛型的型別沒有父子類子分,在 .NET Framework 4中,變體型別引數僅限於泛型介面和泛型委託型別。 2)泛型介面或泛型委託型別可以同時具有協變和逆變型別引數。 3)變體僅適用於引用型別;如果為 Variant 型別引數指定值型別,則該型別引數對於生成的構造型別是不變的。 4)協變型別建立的是泛型型別子類物件,因此適用於作為函式的返回值。 5)抗變(逆變)型別建立的是泛型型別父類物件,因此適用於作為函式的傳入引數。 從 .NET Framework 4 開始,某些泛型介面具有協變型別引數;例如:IEnumerable<T>、IEnumerator<T>、IQueryable<T> 和 IGrouping<TKey, TElement>。 由於這些介面的所有型別引數都是協變型別引數,因此這些型別引數只用於成員的返回型別。
// covariant 定義了泛型介面是協變的,實現泛型型別中的子類,可以將泛型型別子類賦值給泛型型別父類
    public interface IIndex<out T>
// 派生類中不需要泛型的協變定義了
    public class RectangleCollection : IIndex<Rectangle>
{
}
public static RectangleCollection GetRectangles()
        {
            // 每次都會返回一個新的物件
            return new RectangleCollection();
        }
// 本身是協變的,所以實現的是泛型的子類
            IIndex<Rectangle> rectangles = RectangleCollection.GetRectangles();
           // 協變型別,可以將子類泛型賦值給父類泛型,也就是泛型的協變
            IIndex<Shape> shapes = rectangles;

// contra-variant,定義泛型型別是抗變的,實現泛型型別中的是父類,可以將泛型型別父類賦值給泛型型別子類
    public interface IDisplay<in T>
    {
        void Show(T item);
    }

 //IDisplay<Shape> 泛型的型別是父類的物件
            IDisplay<Shape> shapeDisplay = ShapeDisplay.GetShapeDisplay()/*new ShapeDisplay()*/;
            // 抗變是泛型型別,可以用泛型型別父類物件賦值給泛型型別子類物件
            IDisplay<Rectangle> rectangleDisplay = shapeDisplay;
            rectangleDisplay.Show(rectangles[0]);

8.泛型結構和可空型別 泛型結構和泛型類一樣,只是泛型結構沒有泛型繼承特性。 用一個Nullable<struct or base type name> typeName;就可以定義一個可空型別,因為資料庫中或者xml中允許值型別為null型別,而C#中值型別必須有預設值,如果將值型別轉換為引用會有裝箱操作影響效能,如果用可空的泛型型別卻因為確定了型別而不需要裝箱操作可以很好的提高效能。可空型別使用直接用即可。 可空型別的宣告有,?可以宣告為可空型別:
Nullable<int> x1;
int ? x2;
對可以宣告可空型別,操作時候:
x1 = 10;
x2 = x1;
if(!x1.HasValue)
{
 x1 = null;
}

資料互動時候:
不可空型別直接轉換為可空型別:
int y1 = 4;
int ? x1 = y1;

可空型別轉換為不可空型別,可能會失敗,需要進行強制轉換:
int ? x1 = GetNullableType();
int y1 = (int)x1;
或??宣告為合併符號,定義了預設值如果x1空那麼y1 = 0:
int y1 = x1 ?? 0;


相關推薦

C#特性總結

宣告,用泛型型別T:public class List<T> { } public delegate void Display<T>(T value) {}對泛型有更進一步的限定,必須實現一個介面或派生自父類,或者使用了特定的泛型型別,或者使用了多個泛型型別,例如:public de

C#基礎知識點總結

www. compile win 泛型 override amp 。。 target 類繼承   1.0 什麽是泛型 泛型是C#2.0和CLR(公共語言運行時)升級的一個新特性,泛型為.NET 框架引入了一個叫 type parameters(類型參數)的概念

C#委託與Lambda總結

命名方法委託 class MyDelegateTest { //步驟1,宣告delegate物件 public delegate void MyDelegate(string name); //// 這是我們欲傳遞的方法,它

C#列表List實現二維陣列的功能(令附C#列表List基本用法總結

          // 搜尋有很多種方式,可以使用IndexOf LastIndexOf FindIndex FindLasIndex Find FindLas ,如果只是檢視元素存不,可以使用Exists()方法          // IndexOf() 方法 需要將一個物件做引數, 如果打到,就返回本

C# 的簡單講解和應用

出現 ava 問題 this bsp div arc 但是 int 泛型 什麽是泛型   泛型是 2.0 版 C# 語言和公共語言運行庫 (CLR) 中的一個新功能。泛型將類型參數的概念引入 .NET Framework,類型參數使得設計如下類和方法成為可能:這些類和方

C#約束

bstr 部分 name 一個 參數 list 多個 哈哈 override 本文將對各類泛型約束做一個簡單的總結。 文章一開始,給出演示代碼底稿(在此基礎上修改,演示,說明。) class MyList<T> { List<T> list

C# 特化

但是 data load max fim not str wrap lock C# 泛型不是 C++ 的模板類,並不支持特化和偏特化,但是使用一些技巧可以在一定程度上達到相同的目的。 原文是 po 在 stackoverflow 上的一個回答:A: Generic inde

Java VS C# (偽 VS 真

功能 方法表 語法 一個 class msil 虛方法 strong 反射 一、泛型的本質 泛型是參數化類型的應用,操作的數據類型不限定於特定類型,可以根據實際需要設置不同的數據類型,以實現代碼復用。 二、Java泛型 Java 泛型是Java1.5新增的特性,JVM並

C++ 程序設計與STL模板庫(1)---程序設計簡介及STL簡介與結構

urn 向上 隊列 是把 鏈表 需要 input stack 特定 泛型程序設計的基本概念 編寫不依賴於具體數據類型的程序 將算法從特定的數據結構中抽象出來,成為通用的 C++的模板為泛型程序設計奠定了關鍵的基礎 術語:概念 用來界定具備一定功能的數據類型。例如:

C# 詳解

安全 c++ urn 操作 類型 增加 add 應用 定義 什麽是泛型 我們在編寫程序時,經常遇到兩個模塊的功能非常相似,只是一個是處理int數據,另一個是處理string數據,或者其他自定義的數據類型,但我們沒有辦法,只能分別寫多個方法處理每個數據類型,因為

C#的初步理解

認識 templet 編寫代碼 編譯器 字符串類型 解釋 引用 根據 支持 一.先讓我們認識一下泛型。 1.1什麽是泛型? 1.1.1泛型是程序設計語言的一種特性。允許程序員在強類型程序設計語言中編寫代碼時定義一些可變部分,那些部分在使用前必須作出指

.NET中的集合總結

pro 顯示 接口 www 最重要的 div 類型 項目 .cn 最近對集合相關的命名空間比較感興趣,以前也就用下List<T>, Dictionary<Tkey, TValue>之類,總之,比較小白。點開N多博客,MSDN,StackOverflo

c#——約束

函數 {} 構造 引用 where string c# 泛型 構造函數 例 public void Func<T>(string str)where T:class{} 將泛型T約束為類 T:class class約束,約束為引用類型 T:struct

java集合,簡單總結

容易 對象 並且 集合 需要 api文檔 array object 類型轉換 1.set中裝的對象是沒順序不可以重復。重復的判斷:只要兩個對象equals相等就行了。(要理解的是,並非重復了就報錯,只是存儲時候只有一個,輸出的時候只會輸出一個。) 2.list中的數據對象有

C# 和委托

color program object turn cnblogs urn task pub cdd using System; using System.Collections.Generic; using System.Linq; using System.Text;

C#Dictionary的用法實例詳解

contains code medium 計算 aaa alt -i 硬件 ole 本文以實例形式講述了C#中的泛型Dictionary的用法。具有很好的實用價值。分享給大家供大家參考。具體如下: 泛型最常見的用途是泛型集合,命名空間System.Collections.

26.C++- 編程之類模板(詳解)

泛型編程 info vid 推導 成員函數 multi IT 操作符 com 在上章25.C++- 泛型編程之函數模板(詳解) 學習了後,本章繼續來學習類模板 類模板介紹 和函數模板一樣,將泛型思想應用於類. 編譯器對類模板處理方式和函數模板相同,都是進行2次編

[C#],變體,事件,Lambda表達式

http 技術 有一個 分享圖片 至少 分組 AC oid 添加 定義泛型類型: (1)定義泛型類(在比較泛型的類型值是否為NULL時只能使用==和!=兩個運算符,兩個泛型類不能進行比較,因為不知道它們是否支持運算符),以及如果說要確定用於創建泛型實例的類型,需要了解它們是

C++編程之函數模板

默認參數 soft 需要 mys 信息 ... 數據類型 交互 實現 泛型語義   泛型(Generic Programming),即是指具有在多種數據類型上皆可操作的含意。泛型編程的代表作品 STL 是一種高效、泛型、可交互操作的軟件組件。  泛型編程最初誕生於 C++中

C++線性查找算法——find

除了 const 代碼 指向 筆記 正常 查找算法 文章 con C++泛型線性查找算法——find 《泛型編程和STL》筆記及思考。 線性查找可能是最為簡單的一類查找算法了。他所作用的數據結構為一維線性的空間。這篇文章主要介紹使用 C++ 實現泛型算法 find的過程。