詳解C#擴(kuò)展方法原理及其使用
1、寫(xiě)在前面
今天群里一個(gè)小伙伴問(wèn)了這樣一個(gè)問(wèn)題,擴(kuò)展方法與實(shí)例方法的執(zhí)行順序是什么樣子的,誰(shuí)先誰(shuí)后(這個(gè)問(wèn)題會(huì)在文章結(jié)尾回答)。所以寫(xiě)了這邊文章,力圖從原理角度解釋擴(kuò)展方法及其使用。
以下為主要內(nèi)容:
- 什么是擴(kuò)展方法
- 擴(kuò)展方法原理及自定義擴(kuò)展方法
- 擴(kuò)展方法的使用及其注意事項(xiàng)
2、什么是擴(kuò)展方法
一般而言,擴(kuò)展方法為現(xiàn)有類(lèi)型添加新的方法(從面向?qū)ο蟮慕嵌葋?lái)說(shuō),是為現(xiàn)有對(duì)象添加新的行為)而無(wú)需修改原有類(lèi)型,這是一種無(wú)侵入而且非常安全的方式。擴(kuò)展方法是靜態(tài)的,它的使用和其他實(shí)例方法幾乎沒(méi)有什么區(qū)別。常見(jiàn)的擴(kuò)展方法有Linq擴(kuò)展、有IEnumerable擴(kuò)展等。
先讓我們來(lái)感受一下.NET中自帶的擴(kuò)展方法,其中OrderBy和Aggregate都是系統(tǒng)自帶的擴(kuò)展方法
using System;
using System.Collections.Generic;
using System.Linq;
namespace Test
{
class Program
{
static void Main(string[] args)
{
List<int> lst = new List<int> { 2, 1, 4, 3 };
string result = lst.OrderBy(p => p).Aggregate(string.Empty, (next, p) => next += p + ",");
Console.WriteLine(result);
Console.ReadLine();
}
}
}

是不是感覺(jué)擴(kuò)展方法很優(yōu)美,使用起來(lái)和實(shí)例方法幾乎沒(méi)有區(qū)別。不得不說(shuō).NET在這方面做得很精致,很讓人欽佩,那么接下來(lái)我們來(lái)看看擴(kuò)展方法的原理
3、擴(kuò)展方法原理及自定義擴(kuò)展方法
首先我們,先看看如何自定義擴(kuò)展方法
using System;
using TestExtension;
namespace Test
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("2".ToInt32());
Console.ReadLine();
}
}
}
namespace TestExtension
{
public static class StringExtension
{
public static int ToInt32(this string str)
{
if (int.TryParse(str, out int result))
{
return result;
}
throw new ArgumentException("無(wú)法轉(zhuǎn)換為Int32類(lèi)型");
}
}
}
- 必須是靜態(tài)類(lèi),擴(kuò)展方法也為靜態(tài)方法
- 此方法的第一個(gè)參數(shù)指定方法所操作的類(lèi)型;此參數(shù)前面必須加上 this 修飾符
- 在調(diào)用代碼中,如何不再同一個(gè)命名空間,需要添加 using 指令,導(dǎo)入需要調(diào)用的擴(kuò)展方法所在的命名空間
- 需要注意的是,第一個(gè)this標(biāo)記的參數(shù)并非是實(shí)參,而是標(biāo)識(shí)該擴(kuò)展所指定的類(lèi)型,調(diào)用的時(shí)候只需要提供this后的形參即可
接下來(lái)我們來(lái)探究一下擴(kuò)展方法反編譯后的效果:
這是StringExtension編譯后的代碼,可以看到擴(kuò)展方法在編譯后被標(biāo)記了ExtensionAttribute這個(gè)特性,也就是說(shuō)擴(kuò)展方法在編譯期就已經(jīng)被綁定成擴(kuò)展方法了
.class public auto ansi abstract sealed beforefieldinit TestExtension.StringExtension
extends [System.Runtime]System.Object
{
.custom instance void
[System.Runtime]System.Runtime.CompilerServices.ExtensionAttribute
::.ctor() = (
01 00 00 00
)
// Methods
.method public hidebysig static
int32 ToInt32 (
string str
) cil managed
{
.custom instance void
[System.Runtime]System.Runtime.CompilerServices.ExtensionAttribute
::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x2050
// Code size 31 (0x1f)
.maxstack 2
.locals init (
[0] int32,
[1] bool,
[2] int32
)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldloca.s 0
IL_0004: call bool [System.Runtime]System.Int32::TryParse(string, int32&)
IL_0009: stloc.1
IL_000a: ldloc.1
IL_000b: brfalse.s IL_0012
IL_000d: nop
IL_000e: ldloc.0
IL_000f: stloc.2
IL_0010: br.s IL_001d
IL_0012: ldstr "無(wú)法轉(zhuǎn)換為Int32類(lèi)型"
IL_0017: newobj instance void [System.Runtime]System.ArgumentException::.ctor(string)
IL_001c: throw
IL_001d: ldloc.2
IL_001e: ret
} // end of method StringExtension::ToInt32
} // end of class TestExtension.StringExtension
我們看一下調(diào)用后的效果,和直接調(diào)用靜態(tài)方法一樣TestExtension.StringExtension::ToInt32(string) ,至此,我們已經(jīng)知道了擴(kuò)展方法的使用了,編譯器綁定,底層調(diào)用和靜態(tài)調(diào)用一直,這也解釋了一個(gè)問(wèn)題,就是當(dāng)類(lèi)型為空的時(shí)候,為什么調(diào)用擴(kuò)展方法了
.namespace Test
{
.class private auto ansi beforefieldinit Test.Program
extends [System.Runtime]System.Object
{
// Methods
.method private hidebysig static
void Main (
string[] args
) cil managed
{
// Method begins at RVA 0x207b
// Code size 24 (0x18)
.maxstack 8
.entrypoint
IL_0000: nop
IL_0001: ldstr "2"
IL_0006: call int32 TestExtension.StringExtension::ToInt32(string)
IL_000b: call void [System.Console]System.Console::WriteLine(int32)
IL_0010: nop
IL_0011: call string [System.Console]System.Console::ReadLine()
IL_0016: pop
IL_0017: ret
} // end of method Program::Main
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x2094
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [System.Runtime]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method Program::.ctor
} // end of class Test.Program
}
4、擴(kuò)展方法的使用及其注意事項(xiàng)
擴(kuò)展方法雖然很好用,但是如果我們擴(kuò)展的對(duì)象發(fā)生了版本迭代,則會(huì)增加擴(kuò)展方法失效的風(fēng)險(xiǎn)。
一下是在使用擴(kuò)展方法時(shí)需要注意的地方
- 擴(kuò)展方法與該類(lèi)型中定義的方法具有相同的簽名,編譯器總是綁定到該實(shí)例方法,也就是擴(kuò)展方法永遠(yuǎn)不會(huì)被調(diào)用,這也就回答了題目剛開(kāi)始所說(shuō)的問(wèn)題。同時(shí)這個(gè)地方應(yīng)該是考慮到了程序安全的問(wèn)題,不然很容易出現(xiàn)代碼注入問(wèn)題。
- 當(dāng)出現(xiàn)命名空間不同時(shí),則需要使用using導(dǎo)入命名空間
- 同時(shí)擴(kuò)展方法可以被修飾為internal,public,但需要類(lèi)和擴(kuò)展方法保持同樣的修飾標(biāo)識(shí)
以上就是詳解C#擴(kuò)展方法原理及其使用的詳細(xì)內(nèi)容,更多關(guān)于c# 擴(kuò)展方法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
基于C#實(shí)現(xiàn)一個(gè)溫濕度監(jiān)測(cè)小工具
這篇文章主要為大家詳細(xì)介紹了如何基于C#實(shí)現(xiàn)一個(gè)溫濕度監(jiān)測(cè)小工具,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下2023-01-01
C#.Net基于正則表達(dá)式抓取百度百家文章列表的方法示例
這篇文章主要介紹了C#.Net基于正則表達(dá)式抓取百度百家文章列表的方法,結(jié)合實(shí)例形式分析了C#獲取百度百家文章內(nèi)容及使用正則表達(dá)式匹配標(biāo)題、內(nèi)容、地址等相關(guān)操作技巧,需要的朋友可以參考下2017-08-08
C#編寫(xiě)一個(gè)網(wǎng)游客戶(hù)端的完整步驟
這篇文章主要給大家介紹了關(guān)于C#編寫(xiě)一個(gè)網(wǎng)游客戶(hù)端的相關(guān)資料,文中通過(guò)示例代碼以及圖文介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用C#具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2021-11-11
C#實(shí)現(xiàn)Access通用訪問(wèn)類(lèi)OleDbHelper完整實(shí)例
這篇文章主要介紹了C#實(shí)現(xiàn)Access通用訪問(wèn)類(lèi)OleDbHelper,結(jié)合完整實(shí)例形式分析了C#針對(duì)access數(shù)據(jù)庫(kù)的連接、查詢(xún)、遍歷、分頁(yè)顯示等相關(guān)操作技巧,需要的朋友可以參考下2017-02-02
js驗(yàn)證電話號(hào)碼手機(jī)號(hào)碼的正則表達(dá)式
本篇文章主要是對(duì)js驗(yàn)證電話號(hào)碼手機(jī)號(hào)碼的正則表達(dá)式進(jìn)行了介紹。需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2014-01-01

