天天看點

C#程式設計:泛型程式設計

本篇目錄

  • ​​泛型程式設計的定義​​
  • ​​泛型程式設計的示例​​
  • ​​簡單示例:商品和盒子​​
  • ​​簡單示例:學生ID​​
  • ​​簡單示例:資料粘合運算​​
  • ​​泛型委托(系統自帶)​​
  • ​​Action無傳回值泛型委托​​
  • ​​Func有傳回值泛型委托​​
  • ​​泛型委托與Lambda表達式​​
  • ​​待拓展​​
  • ​​泛型類說明​​
  • ​​泛型方法說明​​
  • ​​泛型接口說明​​
  • ​​泛型委托說明​​

泛型程式設計的定義

泛型程式設計解決的兩個問題:類型膨脹和成員屬性膨脹

泛型程式設計的示例

簡單示例:商品和盒子

泛型簡單示例:比如小商城裡面對于每一種商品都有一盒子來包裝,但是如果為每一種商品都定義一種盒子去實作包裝,那麼就造成類型膨脹。但是如果都使用一種盒子去實作,而在使用時對商品類型做判斷,那麼就會造成實作盒子包裝的類裡面的成員屬性膨脹。這兩種方式都不是最優解,最優解是通過泛型程式設計來特化商品所需要的盒子,這樣需要包裝是商品的盒子就會在使用的時候,自動特化成特定類型的盒子。
using System;

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            Apple ap = new Apple() { color="red"};
            Book bo = new Book() { name="new book"};
            Box<Apple> box1 = new Box<Apple>() { Cargo = ap };
            Box<Book> box2 = new Box<Book>() { Cargo = bo };

            System.Console.WriteLine(box1.Cargo.color);
            System.Console.WriteLine(box2.Cargo.name);
            System.Console.WriteLine("Hello World!");
            System.Console.ReadKey();
        }

        public class Apple { 
            public string color { set; get; }
        }
        public class Book { 
            public string name { set; get; }
        }

        public class Box<T> { 
            public T Cargo { set;  get; }
        }
    }
}      

簡單示例:學生ID

泛型接口的實作,示例1

假如每個學生都需要有一個ID,那麼可以泛型一個ID接口,實作學生的類可以使用這個接口去實作學生的ID,ID的範圍可以根據具體要求而設定,比如下面示範的int 和ulong兩種資料類型。

using System;

namespace 泛型接口
{
    class Program
    {
        static void Main(string[] args)
        {
            Student<int> stu1 = new Student<int> { };
            stu1.ID = 101;
            stu1.Name = "孫悟空";

            Student<ulong> stu2 = new Student<ulong> { };
            stu2.ID = 20000000000000002;
            stu2.Name = "豬八戒";

            Console.WriteLine("Hello World!");
            System.Console.ReadKey();
        }

        interface StuID<Tid> { 
            Tid ID { set; get; } 
        }

        class Student<Tid> : StuID<Tid> { 
            public Tid ID { set; get; }
            public string Name { set; get; }
        }

    }
}      

簡單示例:資料粘合運算

從以下例子可以看出,但做類似資料粘合的算術運算而沒有使用泛型程式設計的時候,會受到資料類型的制約,以下實作的方法中隻能對于int型數組進行粘合,但是對于double型數組卻無法實作,如果再去實作一個double類型的數組粘合方法,則程式會變得臃腫。

因為方法是類的成員,此時會出現了方法膨脹。

using System;

namespace 資料粘合zip
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] a1 = {1, 2, 3, 4, 5 };
            int[] a2 = {1, 2, 3, 4, 5, 6 };

            double[] a3 = { 1.1, 2.2, 3.3, 4.4, 5.5};
            double[] a4 = { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6 };

            var result = Zip(a1, a2);
            System.Console.WriteLine(string.Join(',',result));
            Console.WriteLine("Hello World!");
            System.Console.ReadKey();
        }

        static int[] Zip(int[] a, int[] b)
        {
            int[] zipped = new int[a.Length + b.Length];
            int a1 = 0, b1 = 0, z1 = 0;
            do
            {
                if (a1 < a.Length)
                    zipped[z1++] = a[a1++];
                if (b1 < b.Length)
                    zipped[z1++] = b[b1++];
            } while (a1 < a.Length || b1 < b.Length);

            return zipped;
        }
    }
}      
如果使用了泛型程式設計,則上面這個例子的問題就可以解決。因為泛型對于資料類型有自動推算功能。
using System;

namespace 資料粘合zip
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] a1 = {1, 2, 3, 4, 5 };
            int[] a2 = {1, 2, 3, 4, 5, 6 };

            double[] a3 = { 1.1, 2.2, 3.3, 4.4, 5.5};
            double[] a4 = { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6 };

            var result = Zip(a1, a2);
            System.Console.WriteLine(string.Join(',',result));

            var result2 = Zip(a3, a4);
            System.Console.WriteLine(string.Join(',', result2));

            Console.WriteLine("Hello World!");
            System.Console.ReadKey();
        }

        static T[] Zip<T>(T[] a, T[] b)
        {
            T[] zipped = new T[a.Length + b.Length];
            int a1 = 0, b1 = 0, z1 = 0;
            do
            {
                if (a1 < a.Length)
                    zipped[z1++] = a[a1++];
                if (b1 < b.Length)
                    zipped[z1++] = b[b1++];
            } while (a1 < a.Length || b1 < b.Length);

            return zipped;
        }
    }
}      

泛型委托(系統自帶)

泛型委托。最常見的泛型委托為:

Action泛型委托(無傳回值)

Func泛型委托(有傳回值)

Action無傳回值泛型委托

Action泛型委托示例
using System;

namespace 泛型委托
{
    class Program
    {
        static void Main(string[] args)
        {
            Action<string> a1 = Say;
            a1("安琪拉");

            Action<int> a2 = MUl;
            a2(1);

            Console.WriteLine("Hello World!");
            System.Console.ReadKey();
        }

        static void Say(string str) {
            System.Console.WriteLine($"hello {str} !");
        }

        static void MUl(int x) {
            System.Console.WriteLine(x*100);
        }
    }
}      

Func有傳回值泛型委托

Func泛型委托示例

Func中最後一個參數表示傳回值類型,前面參數為參數類型

using System;

namespace 泛型委托
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<int, int, int> func1 = add;
            var ret = func1(100, 200);

            Func<double, double, double> func2 = add;

            var ret2 = func2(10.2, 10.3);
            System.Console.WriteLine(ret);
            System.Console.WriteLine(ret2);

            System.Console.WriteLine("Hello World!");
            System.Console.ReadKey();
        }

        static int add(int a, int b) {
            return a + b;
        }
        static double add(double a, double b) {
            return a + b;
        }
    }
}      

泛型委托與Lambda表達式

泛型委托與Lambda表達式

Lambda表達式也就是對于類似以上這種非常簡單的方法,不想去聲明它,而是在使用的時候,随時調用随時聲明,而且是匿名的聲明,這樣就可以避免極其簡單的方法對于程式的污染。 示例如下

using System;

namespace 泛型委托
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<double, double, double> func = (double a, double b)=> { return a + b; };
                                              //這塊為Lambda表達式
     //簡化後 Func<double, double, double> func = (a, b)=> { return a + b; };
            var ret = func(10.2, 10.3);
            System.Console.WriteLine(ret);

            System.Console.WriteLine("Hello World!");
            System.Console.ReadKey();
        }
    }
}      

待拓展

泛型類說明

泛型方法說明

泛型接口說明

泛型委托說明