CSharp擴(kuò)展方法和擴(kuò)展屬性

上傳人:仙*** 文檔編號(hào):57159364 上傳時(shí)間:2022-02-23 格式:DOCX 頁(yè)數(shù):12 大?。?7.69KB
收藏 版權(quán)申訴 舉報(bào) 下載
CSharp擴(kuò)展方法和擴(kuò)展屬性_第1頁(yè)
第1頁(yè) / 共12頁(yè)
CSharp擴(kuò)展方法和擴(kuò)展屬性_第2頁(yè)
第2頁(yè) / 共12頁(yè)
CSharp擴(kuò)展方法和擴(kuò)展屬性_第3頁(yè)
第3頁(yè) / 共12頁(yè)

下載文檔到電腦,查找使用更方便

16 積分

下載資源

還剩頁(yè)未讀,繼續(xù)閱讀

資源描述:

《CSharp擴(kuò)展方法和擴(kuò)展屬性》由會(huì)員分享,可在線閱讀,更多相關(guān)《CSharp擴(kuò)展方法和擴(kuò)展屬性(12頁(yè)珍藏版)》請(qǐng)?jiān)谘b配圖網(wǎng)上搜索。

1、CSharp擴(kuò)展方法 擴(kuò)展方法是實(shí)現(xiàn)新增類(lèi)方法同時(shí)不改變類(lèi)名稱(chēng)的一種技術(shù)??梢圆糠值奶娲颈仨毨^承類(lèi)才能夠?qū)崿F(xiàn)的功能。但是,目前還不能擴(kuò)展類(lèi)的屬性,也不能在不繼承類(lèi)的情況下而直接修改類(lèi)方法。 例如在A MVC Web Application中的,我們想快速了解某個(gè)Action上是否有某個(gè)Attribute. 那我們可以使用這樣的擴(kuò)展方法: ///

/// Gets the method. /// /// Type /// T

2、he instance. /// The method selector. /// MethodInfo public static MethodInfo GetMethod(this T instance, Expression> methodSelector) { // it is not work all method return ((MethodCallExpression)methodSel

3、ector.Body).Method; } ///

/// Gets the method. /// /// /// The instance. /// The method selector. /// MethodInfo public static MethodInfo GetMethod<

4、T>(this T instance, Expression> methodSelector) { return ((MethodCallExpression)methodSelector.Body).Method; } ///

/// Determines whether the specified member has attribute. /// /// The type of the attribute.

5、/// The member. /// /// true if the specified member has attribute; otherwise, false. /// public static bool HasAttribute( this MemberInfo member) where TAttribute : Attribute { return GetAttributes

6、tribute>(member).Length > 0; } ///

/// Gets the attributes. /// /// The type of the attribute. /// The member. /// public static TAttribute[] GetAttributes( this

7、MemberInfo member) where TAttribute : Attribute { var attributes = member.GetCustomAttributes(typeof(TAttribute), true); return (TAttribute[])attributes; } 如何使用,請(qǐng)看下面的代碼,我們使用lambda表達(dá)式獲取某個(gè)方法,然后獲取其上面的Attribute: [Fact] public void GetHttpPostAttributeFromCreateAction()

8、 { // Arrange var controller = GetEmployeeController(new MemeoryEmployeeBoService()); //Act bool hasPostAttribute =controller.GetMethod(e => e.Create(new Employee())) .HasAttribute(); // Assert Assert.True(hasPostAttribute); } 擴(kuò)展

9、方法的實(shí)現(xiàn) 1.首先,我們需要在項(xiàng)目中添加自己的一個(gè)類(lèi)型,此處為ProjectExt,其中的方法與之前定義的方法大致上無(wú)區(qū)別,只是在方法中第一個(gè)參數(shù)前面添加了this關(guān)鍵字,this關(guān)鍵字必須是在方法參數(shù)中第一個(gè)參數(shù)的前面,不可以移位。 view source print? 01.public static ?class ProjectExt 02. { 03. ///

04. /// 向字符串追加字符 05. /// 06. /// 字符串 07. ///

10、me="AppendStr">需要追加的字符串 08. /// 追加完成的字符對(duì)象 09. public static ?string AppendToLeft(this ?string obj,string AppendStr) 10. { 11. return AppendStr + obj; 12. } 13. } 2.像在調(diào)用FCL本身類(lèi)庫(kù)的方法一樣調(diào)用AppendToLeft,我們的代碼看起來(lái)更美麗整潔! view source print? 1.static void Main(string[] ar

11、gs) 2.{ 3. string Tel = "87763445"; 4. Console.WriteLine("Tel:"+ Tel.AppendToLeft("020-")); 5.} 輸出:020-87763445 我們可以淺而易懂的看到兩者之間的區(qū)別,這就是擴(kuò)展方法帶來(lái)的便捷之處,讓我們的代碼更加的整潔,在使用擴(kuò)展方法的時(shí)候必須注意一下幾點(diǎn): 1.第一個(gè)參數(shù)之前必須有this關(guān)鍵字,不可變動(dòng) 2.在添加擴(kuò)展方法的類(lèi)型中,類(lèi)型本身和類(lèi)型所包含的方法必須是靜態(tài)的。 3.由于這里是按類(lèi)型識(shí)別,所以不應(yīng)該將擴(kuò)展方法的第一個(gè)參數(shù)類(lèi)型設(shè)為object,這樣會(huì)造成無(wú)論使用

12、什么類(lèi)型,都會(huì)擴(kuò)展該方法。 4.必須考慮將來(lái)FCL可能會(huì)添加相同的方法,如果FCL在以后的版本中添加了該方法,那么C#會(huì)優(yōu)先選擇FCL所定義的方法。 最后的補(bǔ)充: 擴(kuò)展方法為什么要添加一個(gè)this在前面呢?這引用類(lèi)型的特性有關(guān),this指向調(diào)用者本身,所以改變的也是調(diào)用者本身的實(shí)例,至于為什么在Visual Studio中能找到該方法,這是C#編輯器的功能,其中有一個(gè)搜索的過(guò)程,如果要使用不同命名空間下的擴(kuò)展方法,請(qǐng)?jiān)诖a頂端using該命名空間。另外,由于結(jié)構(gòu)(struct)不能聲明為靜態(tài),但是擴(kuò)展方法必須聲明在靜態(tài)類(lèi)型之中,所以不能在結(jié)構(gòu)(struct)中聲明擴(kuò)展方法,這點(diǎn)必須要

13、注意! 我們?cè)陂_(kāi)發(fā)經(jīng)常要使用Enum類(lèi)型,今天我們用擴(kuò)展方法來(lái)為Enum類(lèi)型加入業(yè)務(wù)邏輯. 有以下的代碼: 1: ///

2: /// StorageProviders 3: /// 4: [Serializable] 5: public enum StorageProviders 6: { 7: /// 8: /// LuceneIo 9:

14、 ///

10: LuceneIo = 0, 11: /// 12: /// LuceneVirtual 13: /// 14: LuceneVirtual = 1 15: } 然后寫(xiě)一個(gè)擴(kuò)展方法: 1: /// 2: /// StorageProvidersExtensions 3: ///

15、4: public static class StorageProvidersExtensions 5: { 6: ///

7: /// Determines whether the specified provider is virtual. 8: /// 9: /// The provider. 10: ///

16、 11: /// true if the specified provider is virtual; otherwise, false. 12: /// 13: public static bool IsVirtual(this StorageProviders provider) 14: { 15: return provider == StorageProviders.LuceneVirtual; 16

17、: } 17: } 好了,讓我們來(lái)看如何使用: 1: [Test] 2: public void TestEnumExtesnsionMethod() 3: { 4: StorageProviders storageProviders = StorageProviders.LuceneVirtual; 5: Assert.IsTrue(storageProviders.IsVirtual()); 6:

18、 } 為對(duì)象添加擴(kuò)展屬性動(dòng)態(tài)獲取數(shù)據(jù) 由于項(xiàng)目需要常常會(huì)遇到為某一個(gè)對(duì)象動(dòng)態(tài)添加屬性的情況,而以前我的實(shí)現(xiàn)方式是創(chuàng)建一個(gè)字典用于存放對(duì)象實(shí)例和它的值,但是往往光這么做是不夠的,例如想在對(duì)象的某個(gè)屬性值改變的時(shí)候做點(diǎn)什么都要寫(xiě)很多的代碼,所以想是不是能夠?qū)⑦@一類(lèi)功能進(jìn)行一下封裝。后來(lái)因?yàn)閷W(xué)習(xí)WPF的緣故,想到依賴(lài)屬性的思想和我需要的功能相近,但是又不能叫我把每一個(gè)想要添加擴(kuò)展的對(duì)象類(lèi)都去繼承DependencyObject吧,而且有些類(lèi)是封閉的不能夠繼承,所以依賴(lài)屬性不能滿足我的需求。不過(guò)說(shuō)到底依賴(lài)屬性還是個(gè)不錯(cuò)的東西,接下來(lái)我們將實(shí)現(xiàn)一個(gè)類(lèi)似的東西 - 擴(kuò)展屬性。

19、 在實(shí)現(xiàn)擴(kuò)展屬性時(shí)我也參考了依賴(lài)屬性的源碼,它的設(shè)計(jì)思想的確很“先進(jìn)”。 1.先來(lái)看看擴(kuò)展屬性的使用方式: 1: private static ExtendProperty InfoProperty = 2: ExtendProperty.RegisterProperty("Info", typeof(string), typeof(UserInfo),"you win"); 3: var user = new UserInfo() { Age=21, Name="maxzhang" }; 4: 5: user.SetValue(InfoProperty, "hello"); 6

20、: string rrr = (string)user.GetValue(InfoProperty); 是不是看著特別像依賴(lài)屬性呢,往下面看: 1: dynamic userDynamic = user.AsDynamic(); 2: rrr= userDynamic.Info; 3: userDynamic.Info = "1"; 4: userDynamic.Age = 50; 5: rrr = userDynamic.Info; 我為擴(kuò)展屬性添加了動(dòng)態(tài)性使對(duì)象屬性的創(chuàng)建和訪問(wèn)更加方便,這里如果Info屬性在前面沒(méi)有用RegisterProperty方法定義過(guò)它會(huì)自動(dòng)生成一個(gè)擴(kuò)展

21、屬性且添加屬性值.如果訪問(wèn)了它的普通屬性屬性也是正常使用的。以上兩個(gè)例子中 UserInfo類(lèi)的定義是 public class UserInfo : ExtendObject { public string Name { set; get; } public int Age { set; get; }},你可能會(huì)問(wèn)這不是和依賴(lài)屬性一樣嗎?只是把繼承DependencyObject換成了繼承你自己寫(xiě)的ExtendObject 了。是的這樣看是差不多的,不過(guò)以上的情況還是有一個(gè)好處的就是我可以在任何項(xiàng)目里引用它。 如果遇到了不能繼承的情況呢,其實(shí)這種情況有很多。接… publ

22、ic class UserInfo1 { public string Name{set;get;} } 這個(gè)類(lèi)不繼承任何類(lèi)。 解決它這里引入了新的擴(kuò)展類(lèi)型AttachObject : 1: AttachObject user1Aobj = new AttachObject(user1); 2: var dyuser = user1Aobj.ToDynamicAttachObject(); 3: //var dyuser = user1.ToDynamicAttachObject(); 4: dyuser.Memo = "haha my name i's maxzhang......

23、"; 5: rrr = dyuser.Memo; 其實(shí)AttachObject 類(lèi)型也是一個(gè)ExtendObject 可以把它看成是一個(gè)ExtendObject 的裝飾。 2.下面我們來(lái)看看這些都是怎么實(shí)現(xiàn)的 (1).ExtendProperty 與依賴(lài)屬性類(lèi)似,在ExtendProperty類(lèi)中用了一個(gè)Dictionary來(lái)存儲(chǔ)系統(tǒng)中要用到的擴(kuò)展屬性,這樣實(shí)現(xiàn)也達(dá)到了節(jié)省內(nèi)存資源的目地。且這個(gè)類(lèi)的構(gòu)造器是一個(gè)private的,這樣也就實(shí)現(xiàn)了一個(gè)單例模式,只有在RegisterProperty方法才能創(chuàng)造出一個(gè)ExtendProper

24、ty來(lái). RegisterPropertypublic static ExtendProperty RegisterProperty(string propertyName, Type propertyType, Type ownerType,object defaultValue) { var property = new ExtendProperty(propertyName, propertyType,ownerType); property.OverrideDefaultValue(ownerType, defaultValue); ExtendPropertysProv

25、ider.Set(property.GetHashCode(), property); return property; } 用GetHashCode來(lái)標(biāo)示我們這個(gè)屬性的唯一性,這里我重寫(xiě)了這個(gè)函數(shù)它的值是this.ownerType.GetHashCode()^this.propertyName.GetHashCode(),也就是說(shuō)用注冊(cè)這個(gè)屬性的類(lèi)型和屬性的名稱(chēng)確定了這個(gè)擴(kuò)展屬性。我們看到OverrideDefaultValue這個(gè)方法它是用來(lái)重寫(xiě)屬性的默認(rèn)值的,在這個(gè)系統(tǒng)中如果某個(gè)對(duì)象的擴(kuò)展屬性沒(méi)有賦過(guò)值或說(shuō)沒(méi)有改變過(guò),那么它應(yīng)該在訪問(wèn)這個(gè)屬性的時(shí)候取得一個(gè)默認(rèn)值而且這個(gè)默認(rèn)值

26、應(yīng)該是所有相同注冊(cè)類(lèi)型的對(duì)象共有的,而在用普通屬性存儲(chǔ)的對(duì)象中我們實(shí)例化對(duì)象后會(huì)在每一個(gè)對(duì)象中保存相應(yīng)的默認(rèn)值,這樣無(wú)疑是浪費(fèi)了內(nèi)存。而且OverrideDefaultValue與AddOwner方法一起使用可以達(dá)到屬性繼承的目的。我們來(lái)看看AddOwner方法的實(shí)現(xiàn):AddOwnerpublic ExtendProperty AddOwner(Type ownerType,object defaultValue) { int newOwnerHash = ownerType.GetHashCode() ^ this.PropertyName.GetHashCode(); if(defa

27、ultValue!=null) this.OverrideDefaultValue(ownerType, defaultValue); ExtendPropertysProvider.Set(newOwnerHash, this); return this; } 使用AddOwner方法我們就在原有的擴(kuò)展屬性上添加了一個(gè)指向它的引用從而達(dá)到繼承的目地,怎么重寫(xiě)屬性默認(rèn)值呢?其實(shí)很簡(jiǎn)單默認(rèn)值在擴(kuò)展屬性中保存在一個(gè)的字典中通過(guò)不同的類(lèi)型我們就可以訪問(wèn)不同類(lèi)型的相同屬性的默認(rèn)值了。 (2).ExtendObject 這里ExtendObject就沒(méi)什么好說(shuō)

28、的了,原理就是其內(nèi)部有一個(gè)Dictionary propertyValues 存儲(chǔ)著不同對(duì)象的值,用自身的GetHashCode ^ 擴(kuò)展屬性的HashCode 確定值的唯一性。 ExtendObject的源碼,呵呵 public class ExtendObject { protected Dictionary propertyValues = new Dictionary(); private Type OwnerType = null; public ExtendObject() { Ow

29、nerType = this.GetType(); } public override int GetHashCode() { return base.GetHashCode(); } public virtual object GetOwner() { return this; } protected void AttachOwner(Type ownerType) { this.OwnerType = ownerType; } public bool IsExtendProperty(string propertyName) { return

30、 !OwnerType.GetProperties().Any(p => p.Name == propertyName); ; } protected ExtendProperty GetProperty(string name) { int propertyKey = OwnerType.GetHashCode() ^ name.GetHashCode(); var property = ExtendPropertysProvider.Get(propertyKey); return property; } public object GetValue(ExtendP

31、roperty property) { int propertyHash = property.GetHashCode(); int key = this.GetHashCode() ^ propertyHash; object result = null; if (!propertyValues.TryGetValue(key, out result)) { result = property.GetDefaultValue(this.OwnerType); } return result; } public bool ClearValue(ExtendPr

32、operty property) { bool result = false; int propertyHash = property.GetHashCode(); int key = this.GetHashCode() ^ propertyHash; if (propertyValues.Keys.Any(k => k == key)) { propertyValues.Remove(key); result = true; } return result; } public void SetValue(ExtendProperty property, ob

33、ject value) { var changedItemArgs = new ExtendPropertyValueChangedArgs(); int propertyHash = property.GetHashCode(); int key = this.GetHashCode() ^ propertyHash; if (propertyValues.Keys.Any(k => k == key)) { changedItemArgs.OldValue = propertyValues[key]; propertyValues[key] = value; } e

34、lse { changedItemArgs.OldValue = null; propertyValues.Add(key, value); } changedItemArgs.Item = GetOwner(); changedItemArgs.PropertyType = property.PropertyType; changedItemArgs.PropertyName = property.PropertyName; changedItemArgs.NewValue = value; property.OnValueChanged(changedItemAr

35、gs); } public bool ClearValue(string propertyName) { var property = this.GetProperty(propertyName); if (property != null) return this.ClearValue(property); return false; } public object GetValue(string propertyName) { var property = this.GetProperty(propertyName); if (property != n

36、ull) return this.GetValue(property); return null; } public void SetValue(string propertyName, object value) { var property = this.GetProperty(propertyName); if (property != null) { this.SetValue(property, value); } else { var newProperty = ExtendProperty.RegisterProperty(propertyN

37、ame, typeof(object), OwnerType); this.SetValue(newProperty, value); } } public ExtendDynamicObject AsDynamic() { return new ExtendDynamicObject(this); } } 不過(guò)這里還是有一個(gè)小小的技巧的就是OwnerType這個(gè)屬性和AttachOwner方法,默認(rèn)的OwnerType屬性的值是擴(kuò)展對(duì)象本身的Type,但是通過(guò) AttachOwner方法我們可以改變這個(gè)屬性從而達(dá)到將不繼承自ExtendObject類(lèi)型的對(duì)象裝飾成E

38、xtendObject 對(duì)象的目地。 (3).也就是AttachObject AttachObject類(lèi)通過(guò)調(diào)用AttachOwner方法使用了這個(gè)技巧,同時(shí)把同樣為ExtendObject的對(duì)象的屬性統(tǒng)統(tǒng)都Copy過(guò)來(lái). AttachObjectpublic class AttachObject : ExtendObject { private object owner; public AttachObject(object obj) : base() { owner = obj; if (owner is ExtendObject) { Typ

39、e ownerType = typeof(ExtendObject); FieldInfo fInfo = ownerType.GetField("propertyValues", BindingFlags.Default | BindingFlags.NonPublic | BindingFlags.Instance); var ownerValues = fInfo.GetValue(owner) as Dictionary; foreach (var v in ownerValues) this.propertyValues.Add(v.Key, v.Value); } this.AttachOwner(owner.GetType()); } public override object GetOwner() { return owner; } public override int GetHashCode() { return owner.GetHashCode(); } }

展開(kāi)閱讀全文
溫馨提示:
1: 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
2: 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
3.本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
5. 裝配圖網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

相關(guān)資源

更多
正為您匹配相似的精品文檔
關(guān)于我們 - 網(wǎng)站聲明 - 網(wǎng)站地圖 - 資源地圖 - 友情鏈接 - 網(wǎng)站客服 - 聯(lián)系我們

copyright@ 2023-2025  zhuangpeitu.com 裝配圖網(wǎng)版權(quán)所有   聯(lián)系電話:18123376007

備案號(hào):ICP2024067431號(hào)-1 川公網(wǎng)安備51140202000466號(hào)


本站為文檔C2C交易模式,即用戶(hù)上傳的文檔直接被用戶(hù)下載,本站只是中間服務(wù)平臺(tái),本站所有文檔下載所得的收益歸上傳人(含作者)所有。裝配圖網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)上載內(nèi)容本身不做任何修改或編輯。若文檔所含內(nèi)容侵犯了您的版權(quán)或隱私,請(qǐng)立即通知裝配圖網(wǎng),我們立即給予刪除!