亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C#泛型的使用及示例詳解

 更新時(shí)間:2021年08月16日 16:04:09   作者:.NET開(kāi)發(fā)菜鳥(niǎo)  
這篇文章主要介紹了C#泛型的使用及示例,本文通過(guò)例子個(gè)大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

這篇文章主要講解C#中的泛型,泛型在C#中有很重要的地位,尤其是在搭建項(xiàng)目框架的時(shí)候。

一、什么是泛型

泛型是C#2.0推出的新語(yǔ)法,不是語(yǔ)法糖,而是2.0由框架升級(jí)提供的功能。

我們?cè)诰幊坛绦驎r(shí),經(jīng)常會(huì)遇到功能非常相似的模塊,只是它們處理的數(shù)據(jù)不一樣。但我們沒(méi)有辦法,只能分別寫(xiě)多個(gè)方法來(lái)處理不同的數(shù)據(jù)類(lèi)型。這個(gè)時(shí)候,那么問(wèn)題來(lái)了,有沒(méi)有一種辦法,用同一個(gè)方法來(lái)處理傳入不同種類(lèi)型參數(shù)的辦法呢?泛型的出現(xiàn)就是專(zhuān)門(mén)來(lái)解決這個(gè)問(wèn)題的。

二、為什么使用泛型

先來(lái)看下面一個(gè)例子:

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

namespace MyGeneric
{
    public class CommonMethod
    {
        /// <summary>
        /// 打印個(gè)int值
        /// </summary>
        /// <param name="iParameter"></param>
        public static void ShowInt(int iParameter)
        {
            Console.WriteLine("This is {0},parameter={1},type={2}",
                typeof(CommonMethod).Name, iParameter.GetType().Name, iParameter);
        }

        /// <summary>
        /// 打印個(gè)string值
        /// </summary>
        /// <param name="sParameter"></param>
        public static void ShowString(string sParameter)
        {
            Console.WriteLine("This is {0},parameter={1},type={2}",
                typeof(CommonMethod).Name, sParameter.GetType().Name, sParameter);
        }

        /// <summary>
        /// 打印個(gè)DateTime值
        /// </summary>
        /// <param name="oParameter"></param>
        public static void ShowDateTime(DateTime dtParameter)
        {
            Console.WriteLine("This is {0},parameter={1},type={2}",
                typeof(CommonMethod).Name, dtParameter.GetType().Name, dtParameter);
        }
    }
}

結(jié)果:

從上面的結(jié)果中我們可以看出這三個(gè)方法,除了傳入的參數(shù)不同外,其里面實(shí)現(xiàn)的功能都是一樣的。在1.0版的時(shí)候,還沒(méi)有泛型這個(gè)概念,那么怎么辦呢。相信很多人會(huì)想到了OOP三大特性之一的繼承,我們知道,C#語(yǔ)言中,object是所有類(lèi)型的基類(lèi),將上面的代碼進(jìn)行以下優(yōu)化:

public static void ShowObject(object oParameter)
{
      Console.WriteLine("This is {0},parameter={1},type={2}",
         typeof(CommonMethod), oParameter.GetType().Name, oParameter);
}

結(jié)果:

從上面的結(jié)果中我們可以看出,使用Object類(lèi)型達(dá)到了我們的要求,解決了代碼的可復(fù)用??赡苡腥藭?huì)問(wèn)定義的是object類(lèi)型的,為什么可以傳入int、string等類(lèi)型呢?原因有二:

1、object類(lèi)型是一切類(lèi)型的父類(lèi)。

2、通過(guò)繼承,子類(lèi)擁有父類(lèi)的一切屬性和行為,任何父類(lèi)出現(xiàn)的地方,都可以用子類(lèi)來(lái)代替。

但是上面object類(lèi)型的方法又會(huì)帶來(lái)另外一個(gè)問(wèn)題:裝箱和拆箱,會(huì)損耗程序的性能。

微軟在C#2.0的時(shí)候推出了泛型,可以很好的解決上面的問(wèn)題。

三、泛型類(lèi)型參數(shù)

在泛型類(lèi)型或方法定義中,類(lèi)型參數(shù)是在其實(shí)例化泛型類(lèi)型的一個(gè)變量時(shí),客戶(hù)端指定的特定類(lèi)型的占位符。 泛型類(lèi)(GenericList<T>)無(wú)法按原樣使用,因?yàn)樗皇钦嬲念?lèi)型;它更像是類(lèi)型的藍(lán)圖。 若要使用GenericList<T>,客戶(hù)端代碼必須通過(guò)指定尖括號(hào)內(nèi)的類(lèi)型參數(shù)來(lái)聲明并實(shí)例化構(gòu)造類(lèi)型。 此特定類(lèi)的類(lèi)型參數(shù)可以是編譯器可識(shí)別的任何類(lèi)型。 可創(chuàng)建任意數(shù)量的構(gòu)造類(lèi)型實(shí)例,其中每個(gè)使用不同的類(lèi)型參數(shù)。

上面例子中的代碼可以修改如下:

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

namespace MyGeneric
{
    public class GenericMethod
    {
        /// <summary>
        /// 泛型方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="tParameter"></param>
        public static void Show<T>(T tParameter)
        {
            Console.WriteLine("This is {0},parameter={1},type={2}",
                typeof(GenericMethod), tParameter.GetType().Name, tParameter.ToString());
        }
    }
}

調(diào)用:

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

namespace MyGeneric
{
    class Program
    {
        static void Main(string[] args)
        {

            int iValue = 123;
            string sValue = "456";
            DateTime dtValue = DateTime.Now;

            Console.WriteLine("***********CommonMethod***************");
            CommonMethod.ShowInt(iValue);
            CommonMethod.ShowString(sValue);
            CommonMethod.ShowDateTime(dtValue);
            Console.WriteLine("***********Object***************");
            CommonMethod.ShowObject(iValue);
            CommonMethod.ShowObject(sValue);
            CommonMethod.ShowObject(dtValue);
            Console.WriteLine("***********Generic***************");
            GenericMethod.Show<int>(iValue);
            GenericMethod.Show<string>(sValue);
            GenericMethod.Show<DateTime>(dtValue);
            Console.ReadKey();
        }
    }
}

顯示結(jié)果:

為什么泛型可以解決上面的問(wèn)題呢?

泛型是延遲聲明的:即定義的時(shí)候沒(méi)有指定具體的參數(shù)類(lèi)型,把參數(shù)類(lèi)型的聲明推遲到了調(diào)用的時(shí)候才指定參數(shù)類(lèi)型。 延遲思想在程序架構(gòu)設(shè)計(jì)的時(shí)候很受歡迎。例如:分布式緩存隊(duì)列、EF的延遲加載等等。

泛型究竟是如何工作的呢?

控制臺(tái)程序最終會(huì)編譯成一個(gè)exe程序,exe被點(diǎn)擊的時(shí)候,會(huì)經(jīng)過(guò)JIT(即時(shí)編譯器)的編譯,最終生成二進(jìn)制代碼,才能被計(jì)算機(jī)執(zhí)行。泛型加入到語(yǔ)法以后,VS自帶的編譯器又做了升級(jí),升級(jí)之后編譯時(shí)遇到泛型,會(huì)做特殊的處理:生成占位符。再次經(jīng)過(guò)JIT編譯的時(shí)候,會(huì)把上面編譯生成的占位符替換成具體的數(shù)據(jù)類(lèi)型。請(qǐng)看下面一個(gè)例子:

Console.WriteLine(typeof(List<>));
Console.WriteLine(typeof(Dictionary<,>));

結(jié)果:

從上面的截圖中可以看出:泛型在編譯之后會(huì)生成占位符。

注意:占位符需要在英文輸入法狀態(tài)下才能輸入,只需要按一次波浪線(xiàn)(數(shù)字1左邊的鍵位)的鍵位即可,不需要按Shift鍵。

1、泛型性能問(wèn)題

請(qǐng)看一下的一個(gè)例子,比較普通方法、Object參數(shù)類(lèi)型的方法、泛型方法的性能。

添加一個(gè)Monitor類(lèi),讓三種方法執(zhí)行同樣的操作,比較用時(shí)長(zhǎng)短:

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

namespace MyGeneric
{
    public class Monitor
    {
        public static void Show()
        {
            Console.WriteLine("****************Monitor******************");
            {
                int iValue = 12345;
                long commonSecond = 0;
                long objectSecond = 0;
                long genericSecond = 0;

                {
                    Stopwatch watch = new Stopwatch();
                    watch.Start();
                    for (int i = 0; i < 100000000; i++)
                    {
                        ShowInt(iValue);
                    }
                    watch.Stop();
                    commonSecond = watch.ElapsedMilliseconds;
                }
                {
                    Stopwatch watch = new Stopwatch();
                    watch.Start();
                    for (int i = 0; i < 100000000; i++)
                    {
                        ShowObject(iValue);
                    }
                    watch.Stop();
                    objectSecond = watch.ElapsedMilliseconds;
                }
                {
                    Stopwatch watch = new Stopwatch();
                    watch.Start();
                    for (int i = 0; i < 100000000; i++)
                    {
                        Show<int>(iValue);
                    }
                    watch.Stop();
                    genericSecond = watch.ElapsedMilliseconds;
                }
                Console.WriteLine("commonSecond={0},objectSecond={1},genericSecond={2}"
                    , commonSecond, objectSecond, genericSecond);
            }
        }

        #region PrivateMethod
        private static void ShowInt(int iParameter)
        {
            //do nothing
        }
        private static void ShowObject(object oParameter)
        {
            //do nothing
        }
        private static void Show<T>(T tParameter)
        {
            //do nothing
        }
        #endregion

    }
}

Main()方法調(diào)用:

Monitor.Show();

結(jié)果:

從結(jié)果中可以看出:泛型方法的性能最高,其次是普通方法,object方法的性能最低。

四、泛型類(lèi)

除了方法可以是泛型以外,類(lèi)也可以是泛型的,例如:

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

namespace MyGeneric
{
    /// <summary>
    /// 泛型類(lèi)
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class GenericClass<T>
    {
        public T _T;
    }
}

Main()方法中調(diào)用:

// T是int類(lèi)型
GenericClass<int> genericInt = new GenericClass<int>();
genericInt._T = 123;
// T是string類(lèi)型
GenericClass<string> genericString = new GenericClass<string>();
genericString._T = "123";

除了可以有泛型類(lèi),也可以有泛型接口,例如:

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

namespace MyGeneric
{
    /// <summary>
    /// 泛型接口
    /// </summary>
    public interface IGenericInterface<T>
    {
        //泛型類(lèi)型的返回值
        T GetT(T t);
    }
}

也可以有泛型委托:

public delegate void SayHi<T>(T t);//泛型委托

注意:

1、泛型在聲明的時(shí)候可以不指定具體的類(lèi)型,但是在使用的時(shí)候必須指定具體類(lèi)型,例如:

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

namespace MyGeneric
{
    /// <summary>
    /// 使用泛型的時(shí)候必須指定具體類(lèi)型,
    /// 這里的具體類(lèi)型是int
    /// </summary>
    public class CommonClass :GenericClass<int>
    {
    }
}

如果子類(lèi)也是泛型的,那么繼承的時(shí)候可以不指定具體類(lèi)型,例如:

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

namespace MyGeneric
{
    /// <summary>
    /// 使用泛型的時(shí)候必須指定具體類(lèi)型,
    /// 這里的具體類(lèi)型是int
    /// </summary>
    public class CommonClass :GenericClass<int>
    {
    }

    /// <summary>
    /// 子類(lèi)也是泛型的,繼承的時(shí)候可以不指定具體類(lèi)型
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class CommonClassChild<T>:GenericClass<T>
    {

    }
}

2、類(lèi)實(shí)現(xiàn)泛型接口也是這種情況,例如:

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

namespace MyGeneric
{
    /// <summary>
    /// 必須指定具體類(lèi)型
    /// </summary>
    public class Common : IGenericInterface<string>
    {
        public string GetT(string t)
        {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// 可以不知道具體類(lèi)型,但是子類(lèi)也必須是泛型的
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class CommonChild<T> : IGenericInterface<T>
    {
        public T GetT(T t)
        {
            throw new NotImplementedException();
        }
    }
}

五、泛型約束

先來(lái)看看下面的一個(gè)例子:

定義一個(gè)People類(lèi),里面有屬性和方法:

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

namespace MyGeneric
{
    public interface ISports
    {
        void Pingpang();
    }

    public interface IWork
    {
        void Work();
    }


    public class People
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public void Hi()
        {
            Console.WriteLine("Hi");
        }
    }

    public class Chinese : People, ISports, IWork
    {
        public void Tradition()
        {
            Console.WriteLine("仁義禮智信,溫良恭儉讓");
        }
        public void SayHi()
        {
            Console.WriteLine("吃了么?");
        }

        public void Pingpang()
        {
            Console.WriteLine("打乒乓球...");
        }

        public void Work()
        {
            throw new NotImplementedException();
        }
    }

    public class Hubei : Chinese
    {
        public Hubei(int version)
        { }

        public string Changjiang { get; set; }
        public void Majiang()
        {
            Console.WriteLine("打麻將啦。。");
        }
    }


    public class Japanese : ISports
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public void Hi()
        {
            Console.WriteLine("Hi");
        }
        public void Pingpang()
        {
            Console.WriteLine("打乒乓球...");
        }
    }
}

在Main()方法里面實(shí)例化:

People people = new People()
{
        Id = 123,
        Name = "走自己的路"
};
Chinese chinese = new Chinese()
{
        Id = 234,
        Name = "晴天"
};
Hubei hubei = new Hubei(123)
{
        Id = 345,
        Name = "流年"
};
Japanese japanese = new Japanese()
{
        Id = 7654,
        Name = "werwer"
};

這時(shí)有一個(gè)需求:需要打印出Id和Name屬性的值,將ShowObject()方法修改如下:

但是這樣修改報(bào)錯(cuò)了:object類(lèi)里面沒(méi)有Id和Name屬性,可能會(huì)有人說(shuō),強(qiáng)制類(lèi)型轉(zhuǎn)換一下就行了?。?/p>

public static void ShowObject(object oParameter)
{
         Console.WriteLine("This is {0},parameter={1},type={2}",
         typeof(CommonMethod), oParameter.GetType().Name, oParameter);

         Console.WriteLine($"{((People)oParameter).Id}_{((People)oParameter).Name}");
}

這樣修改以后,代碼不會(huì)報(bào)錯(cuò)了,這時(shí)我們?cè)贛ain()方法里面調(diào)用:

CommonMethod.ShowObject(people);
 CommonMethod.ShowObject(chinese);
 CommonMethod.ShowObject(hubei);
 CommonMethod.ShowObject(japanese);

結(jié)果:

可以看出程序報(bào)錯(cuò)了,因?yàn)镴apanese沒(méi)有繼承自People,這里類(lèi)型轉(zhuǎn)換的時(shí)候失敗了。這樣會(huì)造成類(lèi)型不安全的問(wèn)題。那么怎么解決類(lèi)型不安全的問(wèn)題呢?那就是使用泛型約束。

所謂的泛型約束,實(shí)際上就是約束的類(lèi)型T。使T必須遵循一定的規(guī)則。比如T必須繼承自某個(gè)類(lèi),或者T必須實(shí)現(xiàn)某個(gè)接口等等。那么怎么給泛型指定約束?其實(shí)也很簡(jiǎn)單,只需要where關(guān)鍵字,加上約束的條件。

泛型約束總共有五種。

約束 s說(shuō)明
T:結(jié)構(gòu) 類(lèi)型參數(shù)必須是值類(lèi)型
T:類(lèi) 類(lèi)型參數(shù)必須是引用類(lèi)型;這一點(diǎn)也適用于任何類(lèi)、接口、委托或數(shù)組類(lèi)型。
T:new() 類(lèi)型參數(shù)必須具有無(wú)參數(shù)的公共構(gòu)造函數(shù)。 當(dāng)與其他約束一起使用時(shí),new() 約束必須最后指定。
T:<基類(lèi)名> 類(lèi)型參數(shù)必須是指定的基類(lèi)或派生自指定的基類(lèi)。
T:<接口名稱(chēng)> 類(lèi)型參數(shù)必須是指定的接口或?qū)崿F(xiàn)指定的接口。 可以指定多個(gè)接口約束。 約束接口也可以是泛型的。

1、基類(lèi)約束

上面打印的方法約束T類(lèi)型必須是People類(lèi)型。

/// <summary>
/// 基類(lèi)約束:約束T必須是People類(lèi)型或者是People的子類(lèi)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tParameter"></param>
public static void Show<T>(T tParameter) where T : People
{
      Console.WriteLine($"{tParameter.Id}_{tParameter.Name}");
      tParameter.Hi();
}

注意:

基類(lèi)約束時(shí),基類(lèi)不能是密封類(lèi),即不能是sealed類(lèi)。sealed類(lèi)表示該類(lèi)不能被繼承,在這里用作約束就無(wú)任何意義,因?yàn)閟ealed類(lèi)沒(méi)有子類(lèi)。

2、接口約束

/// <summary>
/// 接口約束
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <returns></returns>
public static T Get<T>(T t) where T : ISports
{
      t.Pingpang();
      return t;
}

3、引用類(lèi)型約束 class

引用類(lèi)型約束保證T一定是引用類(lèi)型的。

/// <summary>
/// 引用類(lèi)型約束
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <returns></returns>
public static T Get<T>(T t) where T : class
{
      return t;
}

4、值類(lèi)型約束 struct

值類(lèi)型約束保證T一定是值類(lèi)型的。

/// <summary>
/// 值類(lèi)型類(lèi)型約束
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <returns></returns>
public static T Get<T>(T t) where T : struct
{
      return t;
}

5、無(wú)參數(shù)構(gòu)造函數(shù)約束 new()

/// <summary>
/// new()約束
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <returns></returns>
public static T Get<T>(T t) where T : new()
{
     return t;
}

泛型約束也可以同時(shí)約束多個(gè),例如:

public static void Show<T>(T tParameter)
            where T : People, ISports, IWork, new()
{
      Console.WriteLine($"{tParameter.Id}_{tParameter.Name}");
      tParameter.Hi();
      tParameter.Pingpang();
      tParameter.Work();
}

注意:有多個(gè)泛型約束時(shí),new()約束一定是在最后。

六、泛型的協(xié)變和逆變

協(xié)變和逆變是在.NET 4.0的時(shí)候出現(xiàn)的,只能放在接口或者委托的泛型參數(shù)前面,out 協(xié)變covariant,用來(lái)修飾返回值;in:逆變contravariant,用來(lái)修飾傳入?yún)?shù)。

先看下面的一個(gè)例子:

定義一個(gè)Animal類(lèi):

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

namespace MyGeneric
{
    public class Animal
    {
        public int Id { get; set; }
    }
}

然后在定義一個(gè)Cat類(lèi)繼承自Animal類(lèi):

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

namespace MyGeneric
{
    public class Cat :Animal
    {
        public string Name { get; set; }
    }
}

在Main()方法可以這樣調(diào)用:

// 直接聲明Animal類(lèi)
Animal animal = new Animal();
// 直接聲明Cat類(lèi)
Cat cat = new Cat();
// 聲明子類(lèi)對(duì)象指向父類(lèi)
Animal animal2 = new Cat();
// 聲明Animal類(lèi)的集合
List<Animal> listAnimal = new List<Animal>();
// 聲明Cat類(lèi)的集合
List<Cat> listCat = new List<Cat>();

那么問(wèn)題來(lái)了:下面的一句代碼是不是正確的呢?

 List<Animal> list = new List<Cat>();

可能有人會(huì)認(rèn)為是正確的:因?yàn)橐恢籆at屬于Animal,那么一群Cat也應(yīng)該屬于Animal啊。但是實(shí)際上這樣聲明是錯(cuò)誤的:因?yàn)長(zhǎng)ist<Cat>和List<Animal>之間沒(méi)有父子關(guān)系。

這時(shí)就可以用到協(xié)變和逆變了。

// 協(xié)變
 IEnumerable<Animal> List1 = new List<Animal>();
IEnumerable<Animal> List2 = new List<Cat>();

F12查看定義:

可以看到,在泛型接口的T前面有一個(gè)out關(guān)鍵字修飾,而且T只能是返回值類(lèi)型,不能作為參數(shù)類(lèi)型,這就是協(xié)變。使用了協(xié)變以后,左邊聲明的是基類(lèi),右邊可以聲明基類(lèi)或者基類(lèi)的子類(lèi)。

協(xié)變除了可以用在接口上面,也可以用在委托上面:

 Func<Animal> func = new Func<Cat>(() => null);

除了使用.NET框架定義好的以為,我們還可以自定義協(xié)變,例如:

/// <summary>
/// out 協(xié)變 只能是返回結(jié)果
/// </summary>
/// <typeparam name="T"></typeparam>
public interface ICustomerListOut<out T>
{
     T Get();
}

public class CustomerListOut<T> : ICustomerListOut<T>
{
     public T Get()
     {
         return default(T);
     }
}

使用自定義的協(xié)變:

// 使用自定義協(xié)變
 ICustomerListOut<Animal> customerList1 = new CustomerListOut<Animal>();
 ICustomerListOut<Animal> customerList2 = new CustomerListOut<Cat>();

在來(lái)看看逆變。

在泛型接口的T前面有一個(gè)In關(guān)鍵字修飾,而且T只能方法參數(shù),不能作為返回值類(lèi)型,這就是逆變。請(qǐng)看下面的自定義逆變:

/// <summary>
/// 逆變 只能是方法參數(shù)
/// </summary>
/// <typeparam name="T"></typeparam>
public interface ICustomerListIn<in T>
{
     void Show(T t);
}

public class CustomerListIn<T> : ICustomerListIn<T>
{
     public void Show(T t)
     {
     }
}

使用自定義逆變:

// 使用自定義逆變
ICustomerListIn<Cat> customerListCat1 = new CustomerListIn<Cat>();
 ICustomerListIn<Cat> customerListCat2 = new CustomerListIn<Animal>();

協(xié)變和逆變也可以同時(shí)使用,看看下面的例子:

/// <summary>
/// inT 逆變
/// outT 協(xié)變
/// </summary>
/// <typeparam name="inT"></typeparam>
/// <typeparam name="outT"></typeparam>
public interface IMyList<in inT, out outT>
{
     void Show(inT t);
     outT Get();
     outT Do(inT t);
}

public class MyList<T1, T2> : IMyList<T1, T2>
{

     public void Show(T1 t)
     {
          Console.WriteLine(t.GetType().Name);
     }

     public T2 Get()
     {
          Console.WriteLine(typeof(T2).Name);
          return default(T2);
      }

      public T2 Do(T1 t)
      {
           Console.WriteLine(t.GetType().Name);
           Console.WriteLine(typeof(T2).Name);
           return default(T2);
       }
 }

使用:

IMyList<Cat, Animal> myList1 = new MyList<Cat, Animal>();
 IMyList<Cat, Animal> myList2 = new MyList<Cat, Cat>();//協(xié)變
 IMyList<Cat, Animal> myList3 = new MyList<Animal, Animal>();//逆變
IMyList<Cat, Animal> myList4 = new MyList<Animal, Cat>();//逆變+協(xié)變

七、泛型緩存

在前面我們學(xué)習(xí)過(guò),類(lèi)中的靜態(tài)類(lèi)型無(wú)論實(shí)例化多少次,在內(nèi)存中只會(huì)有一個(gè)。靜態(tài)構(gòu)造函數(shù)只會(huì)執(zhí)行一次。在泛型類(lèi)中,T類(lèi)型不同,每個(gè)不同的T類(lèi)型,都會(huì)產(chǎn)生一個(gè)不同的副本,所以會(huì)產(chǎn)生不同的靜態(tài)屬性、不同的靜態(tài)構(gòu)造函數(shù),請(qǐng)看下面的例子:

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

namespace MyGeneric
{
    public class GenericCache<T>
    {
        static GenericCache()
        {
            Console.WriteLine("This is GenericCache 靜態(tài)構(gòu)造函數(shù)");
            _TypeTime = string.Format("{0}_{1}", typeof(T).FullName, DateTime.Now.ToString("yyyyMMddHHmmss.fff"));
        }

        private static string _TypeTime = "";

        public static string GetCache()
        {
            return _TypeTime;
        }
    }
}

然后新建一個(gè)測(cè)試類(lèi),用來(lái)測(cè)試GenericCache類(lèi)的執(zhí)行順序:

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

namespace MyGeneric
{
    public class GenericCacheTest
    {
        public static void Show()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine(GenericCache<int>.GetCache());
                Thread.Sleep(10);
                Console.WriteLine(GenericCache<long>.GetCache());
                Thread.Sleep(10);
                Console.WriteLine(GenericCache<DateTime>.GetCache());
                Thread.Sleep(10);
                Console.WriteLine(GenericCache<string>.GetCache());
                Thread.Sleep(10);
                Console.WriteLine(GenericCache<GenericCacheTest>.GetCache());
                Thread.Sleep(10);
            }
        }
    }
}

Main()方法里面調(diào)用:

GenericCacheTest.Show();

結(jié)果:

從上面的截圖中可以看出,泛型會(huì)為不同的類(lèi)型都創(chuàng)建一個(gè)副本,所以靜態(tài)構(gòu)造函數(shù)會(huì)執(zhí)行5次。 而且每次靜態(tài)屬性的值都是一樣的。利用泛型的這一特性,可以實(shí)現(xiàn)緩存。

注意:只能為不同的類(lèi)型緩存一次。泛型緩存比字典緩存效率高。泛型緩存不能主動(dòng)釋放

到此這篇關(guān)于C#泛型的使用及示例的文章就介紹到這了,更多相關(guān)C#泛型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C#使用LINQ查詢(xún)文件列表并找出最大文件

    C#使用LINQ查詢(xún)文件列表并找出最大文件

    在現(xiàn)代 C# 開(kāi)發(fā)中,LINQ (Language Integrated Query) 提供了一種強(qiáng)大而優(yōu)雅的方式來(lái)處理集合數(shù)據(jù),本文將詳細(xì)介紹如何使用 LINQ 查詢(xún)文件系統(tǒng)中的文件,并找出最大的文件數(shù)量,需要的朋友可以參考下
    2024-10-10
  • c#抽簽系統(tǒng)的實(shí)現(xiàn)示例

    c#抽簽系統(tǒng)的實(shí)現(xiàn)示例

    本文主要介紹了c#抽簽系統(tǒng)的實(shí)現(xiàn)示例,一個(gè)基于c#的簡(jiǎn)單抽簽系統(tǒng),可以重新導(dǎo)入數(shù)據(jù),清空數(shù)據(jù)。文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • 原生實(shí)現(xiàn)C#與Lua相互調(diào)用方法(Unity3D可用)

    原生實(shí)現(xiàn)C#與Lua相互調(diào)用方法(Unity3D可用)

    Lua是一種很好的擴(kuò)展性語(yǔ)言,Lua解釋器被設(shè)計(jì)成一個(gè)很容易嵌入到宿主程序的庫(kù),下面這篇文章主要給大家介紹了關(guān)于原生實(shí)現(xiàn)C#與Lua相互調(diào)用方法,Unity3D可用的相關(guān)資料,需要的朋友可以參考下
    2022-04-04
  • C# 執(zhí)行bat批處理文件的小例子

    C# 執(zhí)行bat批處理文件的小例子

    這篇文章介紹了C# 執(zhí)行bat批處理文件的小例子,有需要的朋友可以參考一下
    2013-10-10
  • C#中Arraylist的sort函數(shù)用法實(shí)例分析

    C#中Arraylist的sort函數(shù)用法實(shí)例分析

    這篇文章主要介紹了C#中Arraylist的sort函數(shù)用法,較為詳細(xì)的分析了ArrayList的sort函數(shù)的功能、定義及具體使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-10-10
  • C#使用Socket實(shí)現(xiàn)通信的方法示例

    C#使用Socket實(shí)現(xiàn)通信的方法示例

    這篇文章主要介紹了C#使用Socket實(shí)現(xiàn)通信的方法示例,文章按照 Socket 的 創(chuàng)建、連接、傳輸數(shù)據(jù)、釋放資源的過(guò)程來(lái)寫(xiě),給出方法、參數(shù)的詳細(xì)信息,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下
    2024-06-06
  • C#獲取局域網(wǎng)MAC地址的簡(jiǎn)單實(shí)例

    C#獲取局域網(wǎng)MAC地址的簡(jiǎn)單實(shí)例

    這篇文章主要介紹了C#獲取局域網(wǎng)MAC地址的簡(jiǎn)單實(shí)例,有需要的朋友可以參考一下
    2013-11-11
  • C# 獲取枚舉值的簡(jiǎn)單實(shí)例

    C# 獲取枚舉值的簡(jiǎn)單實(shí)例

    這篇文章介紹了C# 獲取枚舉值的簡(jiǎn)單實(shí)例,有需要的朋友可以參考一下
    2013-09-09
  • C#中struct和class的區(qū)別詳解

    C#中struct和class的區(qū)別詳解

    這篇文章主要介紹了C#中struct和class的區(qū)別,對(duì)C#初學(xué)者來(lái)說(shuō)是需要牢固掌握的,需要的朋友可以參考下
    2014-08-08
  • C#畫(huà)筆Pen繪制自定義線(xiàn)的帽子

    C#畫(huà)筆Pen繪制自定義線(xiàn)的帽子

    這篇文章主要介紹了C#畫(huà)筆Pen繪制自定義線(xiàn)的帽子,實(shí)例分析了畫(huà)筆Pen的使用技巧,需要的朋友可以參考下
    2015-06-06

最新評(píng)論