C#優(yōu)雅的實(shí)現(xiàn)INotifyPropertyChanged接口
INotifyPropertyChanged接口在WPF或WinFrom程序中使用還是經(jīng)常用到,常用于通知界面屬性變更。標(biāo)準(zhǔn)寫法如下:
class NotifyObject : INotifyPropertyChanged { private int number; public int Number { get { return number; } set { number = value; OnPropertyChanged("Number"); } } private string text; public string Text { get { return text; } set { text = value; OnPropertyChanged("Text"); } } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName = "") { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } }
這種寫法的兩個(gè)問(wèn)題是
- 對(duì)屬性名使用了字符串硬編碼,容易寫錯(cuò),也不方便重構(gòu)
- 冗余代碼,如果屬性較多的時(shí)候?qū)懙孟胪?/li>
我在博客文章使用CallerMemberName簡(jiǎn)化InotifyPropertyChanged的實(shí)現(xiàn)中介紹了通過(guò)Caller Information解決屬性名稱字符串硬編碼的問(wèn)題。但是仍然不能解決冗余代碼的問(wèn)題。對(duì)于第二個(gè)問(wèn)題,往往是通過(guò)AOP的方式實(shí)現(xiàn),一般的實(shí)現(xiàn)方式有兩種:
- 通過(guò)代理對(duì)象封裝
- 通過(guò)編譯期間代碼注入的方式實(shí)現(xiàn)
我增在項(xiàng)目中使用過(guò)DynamicObject封裝來(lái)實(shí)現(xiàn)過(guò),主要原理是用實(shí)現(xiàn)一個(gè)PocoNotifyWrapper的DynamicObject類,托管其屬性的讀寫動(dòng)作,并附加IntofyPropertyChanged接口實(shí)現(xiàn)。
這種方式是動(dòng)態(tài)的AOP了,是一個(gè)通用的方式,并且擴(kuò)展性比較器,可以通過(guò)繼承PocoNotifyWrapper來(lái)實(shí)現(xiàn)多態(tài)。用它做ViewMode層還是比較方便。
不過(guò)一個(gè)不大好的地方是DynamicObject是丟失了屬性類型信息的,有時(shí)綁定時(shí)會(huì)出錯(cuò)(如將一個(gè)TextBox的Text綁定到一個(gè)封裝后的Int類型對(duì)象時(shí)會(huì)不進(jìn)行自動(dòng)類型轉(zhuǎn)換)。要解決它還需要實(shí)現(xiàn)一些其它的接口,實(shí)現(xiàn)起來(lái)還是有些復(fù)雜的,并且項(xiàng)目進(jìn)度比較緊張,沒(méi)有太多時(shí)間來(lái)完善它。
另外一種方式是通過(guò)編譯期間代碼注入方式來(lái)實(shí)現(xiàn):
最開始見的是PostSharp的一個(gè)實(shí)現(xiàn): http://doc.postsharp.net/inotifypropertychanged-add。不過(guò)PostSharp是收費(fèi)的,后來(lái)也逐漸由了許多其它的免費(fèi)的解決方案。本文這里介紹的是一個(gè)開源的解決方案:Fody。
使用它非常簡(jiǎn)單,首先通過(guò)Nuget安裝庫(kù):PM> Install-Package PropertyChanged.Fody
。然后在需要實(shí)現(xiàn)屬性通知的類上加一個(gè)[ImplementPropertyChanged]即可:
[ImplementPropertyChanged] public class Person { public string GivenNames { get; set; } public string FamilyName { get; set; } public string FullName => string.Format("{0} {1}", GivenNames, FamilyName); }
編譯后生成的代碼如下:
public class Person : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; string givenNames; public string GivenNames { get { return givenNames; } set { if (value != givenNames) { givenNames = value; OnPropertyChanged("GivenNames"); OnPropertyChanged("FullName"); } } } string familyName; public string FamilyName { get { return familyName; } set { if (value != familyName) { familyName = value; OnPropertyChanged("FamilyName"); OnPropertyChanged("FullName"); } } } public string FullName { get { return string.Format("{0} {1}", GivenNames, FamilyName); } } public virtual void OnPropertyChanged(string propertyName) { var propertyChanged = PropertyChanged; if (propertyChanged != null) { propertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } }
基本上對(duì)代碼沒(méi)有注入,不需要安裝插件,也不影響調(diào)試,實(shí)現(xiàn)非常簡(jiǎn)單,非常方便。
需要注意的是,如果實(shí)現(xiàn)了INotifyPropertyChanged接口,即使沒(méi)有[ImplementPropertyChanged]標(biāo)記,默認(rèn)也會(huì)注入。
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接
相關(guān)文章
C#先判斷是否存在再創(chuàng)建文件夾或文件與遞歸計(jì)算文件夾大小
這篇文章介紹了C#先判斷是否存在再創(chuàng)建文件夾或文件與遞歸計(jì)算文件夾大小的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07C#學(xué)習(xí)筆記- 淺談數(shù)組復(fù)制,排序,取段,元組
下面小編就為大家?guī)?lái)一篇C#學(xué)習(xí)筆記- 淺談數(shù)組復(fù)制,排序,取段,元組。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-08-08C#無(wú)法打開計(jì)算機(jī)“.”上的 IISADMIN 服務(wù)的解決方法
在使用c#進(jìn)行控制IIS服務(wù)啟動(dòng)停止的時(shí)候,提示:無(wú)法打開計(jì)算機(jī)“.”上的 IISADMIN 服務(wù)2015-01-01unity 如何使用LineRenderer 動(dòng)態(tài)劃線
這篇文章主要介紹了unity 使用LineRenderer 動(dòng)態(tài)劃線的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-04-04C#通過(guò)接口與線程通信(捕獲線程狀態(tài))示例代碼
本文介紹C#通過(guò)接口與線程通信(捕獲線程狀態(tài)),并提供簡(jiǎn)單的示例代碼供參考2013-12-12C#窗體-數(shù)據(jù)庫(kù)連接及登錄功能的實(shí)現(xiàn)案例
這篇文章主要介紹了C#窗體-數(shù)據(jù)庫(kù)連接及登錄功能的實(shí)現(xiàn)案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12C#實(shí)現(xiàn)Nginx平滑加權(quán)輪詢算法
這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)Nginx平滑加權(quán)輪詢算法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07