中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

.NET泛型解析(上)

發布時間:2020-07-30 11:06:54 來源:網絡 閱讀:975 作者:lAlbin 欄目:編程語言

【1】:泛型介紹

泛型是C#2.0中一個重要的新特性,泛型是CLR和編程語言提供的一種特殊機制,它支持另一種形式的代碼重用。

泛型誕生之前:

C#是一種強類型的語言,在沒有泛型沒有被提出之前,我們在使用集合的代碼的時候,每次對其進行轉換都需要隱式的強制轉換,我們都知道所有對象的最終基類是object,我們在每次使用object的時候,無論是變換什么類型都要對其進行強制轉換。

一般情況下,創建泛型類的過程為:從一個現有的具體類開始,逐一將每個類型更改為類型參數,直至達到通用化和可用性的最佳平衡。 創建您自己的泛型類時,需要特別注意以下事項:

  • 將哪些類型通用化為類型參數。

    通常,能夠參數化的類型越多,代碼就會變得越靈活,重用性就越好。 但是,太多的通用化會使其他開發人員難以閱讀或理解代碼。

  • 如果存在約束,應對類型參數應用什么約束

    一條有用的規則是,應用盡可能最多的約束,但仍使您能夠處理必須處理的類型。 例如,如果您知道您的泛型類僅用于引用類型,則應用類約束。 這可以防止您的類被意外地用于值類型,并允許您對 T 使用 as 運算符以及檢查空值。

  • 是否將泛型行為分解為基類和子類。

    由于泛型類可以作為基類使用,此處適用的設計注意事項與非泛型類相同。 請參見本主題后面有關從泛型基類繼承的規則。

  • 是否實現一個或多個泛型接口。

    例如,如果您設計一個類,該類將用于創建基于泛型的集合中的項,則可能必須實現一個接口,如 IComparable,其中 T 是您的類的類型。

【2】:泛型的表示方式

泛型可以為引用類型和值類型還有接口和委托,FCL( DLL程序集包含了.NET框架下的各種DLL )類中定義了一個泛型列表,用來管理一個對象集合,如果我們想要使用這個泛型列表,可以在使用時指定具體數據類型。

泛型的表示為 “T” 如:List<T>, T 表示一個未指定的數據類型,我們可以看一下FCL類中泛型的引用定義:

【3】:泛型的好處

1 : 使代碼更加的簡潔,清晰

 從前面我們也提到了,泛型具備可重用性 , 減少我們代碼量, 使我們的程序更容易開發和維護,舉例 :

 舉例 1 : 在從數據庫中獲取數據庫的時候,我們經常會返回一個DataTable類型,然后將其轉換為List集合. 那么如果沒有泛型的話,我會一般會這樣來做.


public List<TrainingUser> GetTrainingUser(string userId)
        {
            DataTable dt =
                     SqliteHelper.ExecuteDataset(System.Data.CommandType.Text,
                        @"
                        SELECT DISTINCT UserId,TrainingId FROM TRAININGUSER AS TU
                        INNER JOIN [USER] AS U
                         ON U.ID = TU.USERID 
                        JOIN [TRAINING] AS T
                        ON T.ID = TU.TRAININGID
                        WHERE U.ID = '"+userId+"' AND T.ENDTIME > DATETIME('now', 'localtime') AND T.StartTime <= DATETIME('now', 'localtime') ;").Tables[0];
            return DataTableToList(dt);
        }


        private List<TrainingUser> DataTableToList(DataTabledt)
        {
            List<TrainingUser> list = new List<TrainingUser>();
            if(dt. Rows.Count > 0 )
            {
                foreach (DataRow row in dt .Rows)
                {
                    TrainingUser trainingUser = new TrainingUser();
                    if(row["UserId" ] != null)
                    {
                        trainingUser .UserId = row["UserId"].ToString();
                    }
                    if(row["TrainingId" ] != null)
                    {
                        trainingUser.TrainingId = row["TrainingId"].ToString();
                    }
                    list.Add(trainingUser);
                }
            }
            return list;
        }



在方法DataTableToList中,我們傳入了一個DataTable的對象,然后在去循環遍歷每一行的對象值從而去賦值給TrainingUser類型對象,這只是其中的一個方法,如果我們的類型還有 Training/User/Project等類型的話,我們是不是就要寫很多如同DataTableToList這樣的方法呢? 這就體現出了這樣的方式,會造成代碼的冗余以及維護不便問題,那么我們使用泛型來解決

舉例 2 : 使用泛型使上面的代碼更見的清晰,簡潔

 public static List<T> ToList1<T>(DataTable dt) whereT : class, new()
        {
            var prlist =new List<PropertyInfo>();
            Type type = typeof(T);
            Array.ForEach(
                type.GetProperties(),
                p =>
                {
                    if(dt.Columns.IndexOf(p.Name) !=-1)
                    {
                        prlist.Add(p);
                    }
                });
            var oblist = new List<T>();
            // System.Data.SqlTypes.
            foreach(DataRow row in dt.Rows)
            {
                var ob = new T();
                prlist.ForEach(
                    p =>
                    {
                        if(row[p.Name] != DBNull.Value)
                        {
                            p.SetValue(ob, row[p.Name], null);
                        }
                    });
                oblist.Add(ob);
            }
            return oblist;
        }


在上面的這個方法中,我們定義了一個泛型方法,內部實現中是使用了反射的原理,將DataTable轉換為了List(反射后續隨筆中總結,此處只關注泛型部分即可),我們定義了一個靜態的返回值為List<T> ,前面我們說過 T : 代表任意類型(枚舉除外),ToList1<T>,說明我們在調用這個方法的時候,同時要賦予方法名一個類型值,這個類型要和它的返回值類型一致(泛型是類型安全的),Where : 用于限制T的條件 ,例如 where T : class,new() 表示 T 只能是一個類,或者一個類型對象,那么我們在調用的時候就可以這樣來 

public List<TrainingUser>GetTrainingIdByUserId(string userId)
        {
              List<TrainingUser> trainingUserList =  DataTableHelper.ToList1<TrainingUser>(
                    SqliteHelper.ExecuteDataset(System.Data.CommandType.Text,
                        @"
                        SELECT DISTINCT UserId,TrainingId FROM TRAININGUSER AS TU
                        INNER JOIN [USER] AS U
                         ON U.ID = TU.USERID 
                        JOIN [TRAINING] AS T
                        ON T.ID = TU.TRAININGID
                        WHERE U.ID = '"+ userId +"' AND T.ENDTIME > DATETIME('now', 'localtime') AND T.StartTime <= DATETIME('now', 'localtime') ;").Tables[0]);
              return trainingUserList ;
        }


代碼中的DataTableHelper.ToList1<TrainingUser> 即為我們剛才所寫的一個泛型方法,這樣我們可以看到,ToList<T> 傳入的類型為TrainingUser,同時接收者為:List<T> = List<TrainingUser> , 

這樣即便我們后續還有Training/User/Project等其他的類型,我們都可以直接使用DataTableHelper.ToList1<T>(DataTable dt) 來進行類型轉換.

2 : 提升程序的性能

泛型與非泛型相比較而言,性能要好一些,這是為什么? 首先,泛型的類型是由調用者(接收者),去直接賦值的(類型安全的), 那么就不會存在類型轉換的問題,其次, 泛型減少了裝箱和拆箱的過程.

實例 3 : 對于值類型泛型與非泛型的性能比較

        private static void ListTest()
        {
            List<int>list = new List<int>();
            for(inti = 0; i < 100; i++)
            {
                list.Add(i);
                int a = list[i];
            }
            list =null;
        }
        private static void ArrListTest()
        {
            ArrayList arr = new ArrayList();
            for(inti = 0; i <100; i++)
            {
                arr.Add(i);
                int s = (int)arr[i];
            }
            arr = null;
        }
             Stopwatch sw = new Stopwatch();
            sw.Start();
            ListTest();
            Console.WriteLine(" 使用泛型List執行值類型方法歷時 :  "+ sw.Elapsed.ToString());
            sw.Stop();
            Stopwatch sw1 = new Stopwatch();
            sw1.Start();
            ArrListTest();
            Console.WriteLine(" 使用非泛型ArrayList執行值類型方法歷時 :  "+ sw1.Elapsed.ToString());
            sw1.Stop();
            Console.ReadLine();


通過循環 100 來比較,結果為 : 

.NET泛型解析(上)

我們可以看到非泛型的時間要比泛型的時間多出0.0000523秒,泛型比非泛型的時間要多出一些, 那么我們將數值改動一下改為循環 1000次.得出結果為 : .NET泛型解析(上)

泛型比非泛型執行的時間要短0.0000405秒

我們將時間在改動一下,改為 100000呢?結果為 : 

.NET泛型解析(上)

這次差距為 0.0054621 并且隨著執行次數的增長,非泛型相比泛型的時間會逐步的增加,

通過反編譯我們也能看出 : 

泛型:

.NET泛型解析(上).NET泛型解析(上)

非泛型

.NET泛型解析(上).NET泛型解析(上)

從編譯中我們也能看出泛型方法中,接收的為Int32,非泛型為Object,其次泛型不會進行裝箱和拆箱操作,非泛型每次執行都要進行裝箱和拆箱操作.

3 : 類型安全

在實例1 , 2 ,3 中我們都有備注說明,泛型的發送著必須要和接收者進行一致,否則會報異常 ,例如 :

實例 4 :

.NET泛型解析(上)

講一個泛型算法應用于一個具體的類型時,編譯器和CLR能理解開發人員的意圖,并保證只有與指定數據類型兼容的對象才能隨同算法使用,若試圖使用不兼容類型的一個對象,會造成編譯時錯誤,或者運行時拋出異常,

在值類型中,泛型要比非泛型的性能高出很多,在引用類型中,泛型和非泛型的性能相差無幾,但是代碼簡潔了很多。

  此篇至此,下篇主要知識點 :

1、泛型接口

2、泛型委托

3、泛型約束(主要約束,次要約束,構造器約束)

4、泛型類型轉型

5、泛型和反射

6、泛型和屬性

  參考資料 :

        CLR C# Via

        深入理解C#

        https://msdn.microsoft.com/zh-cn/library/sz6zd40f.aspx

        https://msdn.microsoft.com/zh-cn/library/0x6a29h7.aspx


如果你覺得本文對你有幫助的話,請點右下角的推薦,或者直接關注我,后續將不斷更新.NET解析這一系列的文章....


   溫馨提示 :  知識點重溫,不斷總結,思考, 也是一種階段性提高,希望能幫到在讀的你.


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

黄大仙区| 河池市| 海南省| 大化| 天津市| 方城县| 贵州省| 时尚| 通河县| 阳信县| 鹤壁市| 峡江县| 临沂市| 张家口市| 正蓝旗| 镇巴县| 建宁县| 望奎县| 曲水县| 陈巴尔虎旗| 武山县| 新化县| 探索| 黄冈市| 宁南县| 共和县| 高淳县| 大余县| 德钦县| 富民县| 甘德县| 泸西县| 苗栗市| 都兰县| 八宿县| 两当县| 通渭县| 兴宁市| 宜兴市| 聂拉木县| 揭阳市|