主頁 > .NET開發 > C# 基礎知識系列- 5 反射和泛型

C# 基礎知識系列- 5 反射和泛型

2020-09-16 11:36:11 .NET開發

前言

為什么要把反射和泛型放在一起講呢,這里是處于個人對C#的一個很棒的觀感,因為C#的反射是可以獲取泛型里的元素的,而不像Java一個讓我比較難受的地方就是Java的泛型實際編譯的時候會擦除型別資訊,
那么問題來了,什么是泛型,什么又是反射呢?

泛型

請原諒我先介紹泛型,因為沒有泛型基礎直接介紹反射是不完整的,就比如說你辛辛苦苦拿到一個類的反射資訊,等用的時候才發現結果這是一個泛型類,那還得決議這個類的泛型的資訊,這時候就必須先有一個泛型的基礎,
那么什么是泛型呢,先看看百度百科給的定義:

泛型是程式設計語言的一種特性,允許程式員在強型別程式設計語言中撰寫代碼時定義一些可變部分,那些部分在使用前必須作出指明,各種程式設計語言和其編譯器、運行環境對泛型的支持均不一樣,將型別引數化以達到代碼復用提高軟體開發作業效率的一種資料型別,泛型類是參考型別,是堆物件,主要是引入了型別引數這個概念,

額,說實話哈,有一部分我沒看懂他寫的是啥,根據我的理解,泛型就是模板類里套的引數,就好比我們從網上找到一個好看的PPT模板,我們在寫PPT的時候根據我們的主題套用這個模板,然后寫出一個很好看的PPT,被老板表揚升職加薪,嗯,事實上用好了泛型也會升職加薪,

泛型說的籠統一些就是型別引數化的程序,我們之前介紹的List就是一個泛型類,泛型分泛型類/介面和泛型方法,泛型類和泛型介面可以看做是一種,因為它的泛型引數是用在整個結構體里面的(注意不是結構,struct);泛型方法又有引數泛型和回傳值泛型兩種,

宣告一個泛型類/介面

public class Template<T>
{
	private T data;
	public void SetTemplate(T temp)
    {
    	data = https://www.cnblogs.com/c7jie/p/temp;
    }
    public T GetTemplate()
    {
    	return data;
    }
}

上述示例是一個簡單的泛型類,體現了泛型類的特點,在宣告類的時候,宣告一個泛型占位符T ,在下面的屬性、欄位、方法的引數和方法的回傳值都可以使用這個占位符,約定型別一致,

泛型的介面和泛型類是一致的,只不過介面沒有方法的實作內容也就是方法體而已,

泛型類的使用

// 繼續上面的代碼
Template<int> temp = new Template<int>();
temp.SetTemplate(10);
int ten = temp.GetTemplate();

使用泛型類和普通類不同的地方就是,泛型類告訴編譯器你要傳遞的型別,使用<> 做標記,中間寫型別,表示這是一個泛型為XXX的泛型類,通常與其他語言不同的地方是,C#的泛型支持所有型別,意思就是在沒有額外宣告的時候,可以使用任意型別作為泛型引數傳遞,

泛型方法

C#也可以宣告一個方法為泛型方法,方法的泛型宣告是宣告在方法名的后面,引數串列的前方,

public void TemplateMethod<T>(T arg);
public T TemplateMethod1<T>();
public T TemplateMethod2<T>(T arg);

上述三個都是合規的泛型方法宣告,泛型可以是引數,也可以是回傳值,還能既是回傳值又是引數,

那么問題來了,多個泛型引數該怎么宣告?

如下:

public T2 TemplateMothod3<T1,T2>(T1 arg);
public T3 TemplateMothod4<T1,T2,T3>(T1 arg,T2 arg2);

在兩個尖括號中間放入多個泛型,然后用逗號隔開,與引數串列和回傳值的型別一一對應,

泛型方法的使用

TemplateMethod(10);// 方式 1
int it = TemplateMethod1<int>();// 方式 2

由于篇幅和時間的關系(主要是我寫這篇的時候時間有點晚了,,)就不對之前所有的方法進行演示了,

這里簡單介紹一下泛型方法的使用:

  • 方式1 隱藏了一個泛型引數,這是因為如果泛型是引數的話,c#會根據引數的型別自動決議對應的泛型型別是什么,方式1 等同于TemplateMethod<int>(10);
  • 方式2 當泛型引數是回傳值時,必須告知具體的泛型型別,

泛型約束和泛型標記

約束

在實際開發程序中,我們會對一些泛型類的泛型引數進行型別約束,那么泛型約束應該怎么寫呢,看示例:

public void Demo<T>(T arg) where T : 約束內容
public void Demo<T,P>(T arg,P arg1) where T: 約束內容 where P:約束內容

如果對多個引數進行約束,就寫多個where,

泛型的約束有一下幾種:

  • class 表示這是個參考型別
  • new() 表示必須有一個無參建構式
  • struct 表示是個結構體
  • 具體的類名或介面名 表示這個引數必須是這個類的子類或介面的實作類

泛型標記

在C#里有個很有意思的地方,那就是泛型標記,

泛型支持 in/out作為占位符T的前置標記,那這兩個標記是什么意義呢,in表示這個型別引數只能作為引數串列的型別進行傳遞,out表示這是一個回傳值的型別,示例如下:

public T2 Demo<in T1,out T2>(T1 t1);

類和方法的標記大同小易,基本上是一致的,

反射

反射在很多地方都有著使用,這里先簡單的介紹一下C#中的反射相關內容,因為細講的話會涉及到很多東西而且還需要很多前置概念,不過在自己寫框架之前不需要涉及到太多反射的內容,

反射,英文名 reflect,簡單的介紹就是將型別物件化,然后操作這個物件的技術,

我們先創建一個示例類:

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }

    public Person()
    {
        Name = "小李";
        Age = 24;
    }

    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }

    public string SayHi()
    {
        return "你好,我叫" + Name + "我的年紀是 " + Age;
    }
}

獲取一個型別物件

首先需要注意的一個類:Type,這個類是反射技術里的基石,甚至可以說是核心,表示一個類的型別資訊,

那么,我們該如何獲取型別物件呢?在C#中常見的有如下兩個方法:

  1. 使用typeof 關鍵字
Type personType = typeof(Person);
  1. 通過物件,使用GetType 方法
Person person = new Person();
Type personType = person.GetType();

如果我們在撰寫程式的時候,知道要獲取什么類的Type物件的話,建議使用typeof獲取,如果我們只有一個物件,需要通過這個物件進行操作的話,那么最好使用GetType來獲取,

現在我們獲取到了一個Person類的Type物件,可以用來做什么呢?

Type物件的用處

  1. 獲取類名:personType.Name
  2. 獲取所有屬性:personType.GetProperties()
  3. 獲取所有方法:personType.GetMethods()
  4. 獲取所有建構式:personType.GetConstructors()

現在我們一一介紹一下這四種寫法:

第一條:顧名思義,獲取到的結果是Person 這個值,

第二條:該方法會回傳一個型別為PropertyInfo[] 的陣列,這個陣列里包含著所有使用public宣告的屬性,當然也可以通過指定的屬性名獲取屬性物件:personType.GetProperty("Name") 這里會獲取到Person類的Name屬性,

第三條: 獲取該類所有public的方法,并將其封裝成一組型別是MethodInfo的物件陣列,同理,也可以根據方法名進行檢索:personType.GetMethod("SayHi") ,就能獲取對應的SayHi方法,不過,如果有同名方法的話,就可能會出現獲取到的方法不是你想要的了,嗯,這部分會放到精講反射的時候再來細說,

第四條: 獲取建構式,回傳的是一個型別是ConstructorInfo的陣列,表示所有的構造方法,不過可惜的是,沒有根據名字檢索的方法了,因為構造方法就一個名,

使用PropertyInfo動態操作一個物件的屬性值

我們通過上一小節獲取到了一個類的屬性PropertyInfo,現在可以利用這個屬性進行后續的操作:

Person person = new Person();
Type personType = person.GetType();
PropertyInfo prop = personType.GetProperty("Name");//獲取Name屬性
Object value = https://www.cnblogs.com/c7jie/p/prop.GetValue(person);// 獲取 物件 person 的Name屬性值
prop.SetValue(person, "wangyipeng");// 為物件 person的Name屬性設定值為 wangyipeng

需要注意的是:

如果 類的屬性只有get,那么在呼叫SetValue時會報錯,可能要問了,我們知道是有set,但是程式怎么判斷呢?通過prop.CanWrite 的值進行判斷,如果值是true則表明這個屬性可以寫入值,否則不能,

同理,可以很輕易的聯想到如果只有set,那么GetValue也會報錯,與之相對應的就是prop.CanRead屬性了,

使用MethodInfo手動執行一個物件的方法

首先,獲得到一個物件里的某一個方法:

Person person = new Person();
Type personType = person.GetType();
MethodInfo method = personType.GetMethod("SayHi");

現在獲取到了 方法物件,該怎么執行呢?

MethodInfo有一個Invoke方法,這個方法有兩個多載版本,其中有一個是:Invoke(object obj, object[] parameters),第一個引數是要執行的方法所屬的物件,后面的陣列引數是對應方法的引數串列,如果為空則填null即可,該方法有個回傳值,型別是object,如果方法是沒有回傳值的方法,那么Invoke的回傳值就是null,

通過反射獲取一個物件

通過反射獲取一個類的型別物件有幾種方式,先介紹一個不用型別的方式:

Person p = Activator.CreateInstance<Person>();

這種方式有一個要求,Person必須有一個無參的建構式,

第二種方式:

Type personType = typeof(Person);
object p = Activator.CreateInstance(personType);//使用無參建構式
p = Activator.CreateInstance(personType, "小王", 19);//使用Person(string,int)這個建構式

當需要傳遞引數的時候,引數型別必須與對應的建構式一一對應,如果順序變了,可能會出現找不到對應類的問題,

第三種:

//types 是引數串列的引數型別集合,順序與實際引數順序一致
ConstructorInfo cons = personType.GetConstructor(Type[] types);
/*
實際上應該是這個呼叫方
ConstructorInfo cos = personType.GetConstructor(new[]{ typeof(string), typeof(int)});
*/
object person  = cos.Invoke(new object[] {"王先生", 19});

這時候一個簡單的反射介紹就到這里了,反射這里還有一大篇的內容要將,這部分我會放到基礎篇完結之后再做一個統一介紹的,不過先道個歉,沒介紹泛型在反射的應用,

注:代碼里映射的王先生是我一個故人,最近與他有一些糾紛,
更多內容煩請關注我的博客

file

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/56679.html

標籤:C#

上一篇:String.Split分隔字串

下一篇:類與結構體性能對比測驗——以封裝網路心跳包為例

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more