CSharp擴(kuò)展方法和擴(kuò)展屬性
《CSharp擴(kuò)展方法和擴(kuò)展屬性》由會(huì)員分享,可在線閱讀,更多相關(guān)《CSharp擴(kuò)展方法和擴(kuò)展屬性(12頁珍藏版)》請?jiān)谘b配圖網(wǎng)上搜索。
1、CSharp擴(kuò)展方法
擴(kuò)展方法是實(shí)現(xiàn)新增類方法同時(shí)不改變類名稱的一種技術(shù)??梢圆糠值奶娲颈仨毨^承類才能夠?qū)崿F(xiàn)的功能。但是,目前還不能擴(kuò)展類的屬性,也不能在不繼承類的情況下而直接修改類方法。
例如在A MVC Web Application中的,我們想快速了解某個(gè)Action上是否有某個(gè)Attribute. 那我們可以使用這樣的擴(kuò)展方法:
///
2、he instance.
/// The method selector.
///
3、ector.Body).Method;
}
///
4、T>(this T instance,
Expression
5、/// The member.
/// 6、tribute>(member).Length > 0;
}
/// 7、MemberInfo member)
where TAttribute : Attribute
{
var attributes =
member.GetCustomAttributes(typeof(TAttribute), true);
return (TAttribute[])attributes;
}
如何使用,請看下面的代碼,我們使用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 9、方法的實(shí)現(xiàn)
1.首先,我們需要在項(xiàng)目中添加自己的一個(gè)類型,此處為ProjectExt,其中的方法與之前定義的方法大致上無區(qū)別,只是在方法中第一個(gè)參數(shù)前面添加了this關(guān)鍵字,this關(guān)鍵字必須是在方法參數(shù)中第一個(gè)參數(shù)的前面,不可以移位。
view source
print?
01.public static ?class ProjectExt
02. {
03. /// 10、me="AppendStr">需要追加的字符串
08. /// 11、gs)
2.{
3. string Tel = "87763445";
4. Console.WriteLine("Tel:"+ Tel.AppendToLeft("020-"));
5.}
輸出:020-87763445
我們可以淺而易懂的看到兩者之間的區(qū)別,這就是擴(kuò)展方法帶來的便捷之處,讓我們的代碼更加的整潔,在使用擴(kuò)展方法的時(shí)候必須注意一下幾點(diǎn):
1.第一個(gè)參數(shù)之前必須有this關(guān)鍵字,不可變動(dòng)
2.在添加擴(kuò)展方法的類型中,類型本身和類型所包含的方法必須是靜態(tài)的。
3.由于這里是按類型識別,所以不應(yīng)該將擴(kuò)展方法的第一個(gè)參數(shù)類型設(shè)為object,這樣會(huì)造成無論使用 12、什么類型,都會(huì)擴(kuò)展該方法。
4.必須考慮將來FCL可能會(huì)添加相同的方法,如果FCL在以后的版本中添加了該方法,那么C#會(huì)優(yōu)先選擇FCL所定義的方法。
最后的補(bǔ)充:
擴(kuò)展方法為什么要添加一個(gè)this在前面呢?這引用類型的特性有關(guān),this指向調(diào)用者本身,所以改變的也是調(diào)用者本身的實(shí)例,至于為什么在Visual Studio中能找到該方法,這是C#編輯器的功能,其中有一個(gè)搜索的過程,如果要使用不同命名空間下的擴(kuò)展方法,請?jiān)诖a頂端using該命名空間。另外,由于結(jié)構(gòu)(struct)不能聲明為靜態(tài),但是擴(kuò)展方法必須聲明在靜態(tài)類型之中,所以不能在結(jié)構(gòu)(struct)中聲明擴(kuò)展方法,這點(diǎn)必須要 13、注意!
我們在開發(fā)經(jīng)常要使用Enum類型,今天我們用擴(kuò)展方法來為Enum類型加入業(yè)務(wù)邏輯. 有以下的代碼:
1: /// 14、 ///
10: LuceneIo = 0,
11: /// 15、4: public static class StorageProvidersExtensions
5: {
6: /// 16、 11: /// 17、: }
17: }
好了,讓我們來看如何使用:
1: [Test]
2: public void TestEnumExtesnsionMethod()
3: {
4: StorageProviders storageProviders = StorageProviders.LuceneVirtual;
5: Assert.IsTrue(storageProviders.IsVirtual());
6: 18、 }
為對象添加擴(kuò)展屬性動(dòng)態(tài)獲取數(shù)據(jù)
由于項(xiàng)目需要常常會(huì)遇到為某一個(gè)對象動(dòng)態(tài)添加屬性的情況,而以前我的實(shí)現(xiàn)方式是創(chuàng)建一個(gè)字典用于存放對象實(shí)例和它的值,但是往往光這么做是不夠的,例如想在對象的某個(gè)屬性值改變的時(shí)候做點(diǎn)什么都要寫很多的代碼,所以想是不是能夠?qū)⑦@一類功能進(jìn)行一下封裝。后來因?yàn)閷W(xué)習(xí)WPF的緣故,想到依賴屬性的思想和我需要的功能相近,但是又不能叫我把每一個(gè)想要添加擴(kuò)展的對象類都去繼承DependencyObject吧,而且有些類是封閉的不能夠繼承,所以依賴屬性不能滿足我的需求。不過說到底依賴屬性還是個(gè)不錯(cuò)的東西,接下來我們將實(shí)現(xiàn)一個(gè)類似的東西 - 擴(kuò)展屬性。
19、
在實(shí)現(xiàn)擴(kuò)展屬性時(shí)我也參考了依賴屬性的源碼,它的設(shè)計(jì)思想的確很“先進(jìn)”。
1.先來看看擴(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);
是不是看著特別像依賴屬性呢,往下面看:
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)性使對象屬性的創(chuàng)建和訪問更加方便,這里如果Info屬性在前面沒有用RegisterProperty方法定義過它會(huì)自動(dòng)生成一個(gè)擴(kuò)展 21、屬性且添加屬性值.如果訪問了它的普通屬性屬性也是正常使用的。以上兩個(gè)例子中
UserInfo類的定義是 public class UserInfo : ExtendObject { public string Name { set; get; } public int Age { set; get; }},你可能會(huì)問這不是和依賴屬性一樣嗎?只是把繼承DependencyObject換成了繼承你自己寫的ExtendObject 了。是的這樣看是差不多的,不過以上的情況還是有一個(gè)好處的就是我可以在任何項(xiàng)目里引用它。
如果遇到了不能繼承的情況呢,其實(shí)這種情況有很多。接…
publ 22、ic class UserInfo1 { public string Name{set;get;} } 這個(gè)類不繼承任何類。
解決它這里引入了新的擴(kuò)展類型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 類型也是一個(gè)ExtendObject 可以把它看成是一個(gè)ExtendObject 的裝飾。
2.下面我們來看看這些都是怎么實(shí)現(xiàn)的
(1).ExtendProperty
與依賴屬性類似,在ExtendProperty類中用了一個(gè)Dictionary 24、ty來.
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來標(biāo)示我們這個(gè)屬性的唯一性,這里我重寫了這個(gè)函數(shù)它的值是this.ownerType.GetHashCode()^this.propertyName.GetHashCode(),也就是說用注冊這個(gè)屬性的類型和屬性的名稱確定了這個(gè)擴(kuò)展屬性。我們看到OverrideDefaultValue這個(gè)方法它是用來重寫屬性的默認(rèn)值的,在這個(gè)系統(tǒng)中如果某個(gè)對象的擴(kuò)展屬性沒有賦過值或說沒有改變過,那么它應(yīng)該在訪問這個(gè)屬性的時(shí)候取得一個(gè)默認(rèn)值而且這個(gè)默認(rèn)值 26、應(yīng)該是所有相同注冊類型的對象共有的,而在用普通屬性存儲的對象中我們實(shí)例化對象后會(huì)在每一個(gè)對象中保存相應(yīng)的默認(rèn)值,這樣無疑是浪費(fèi)了內(nèi)存。而且OverrideDefaultValue與AddOwner方法一起使用可以達(dá)到屬性繼承的目的。我們來看看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á)到繼承的目地,怎么重寫屬性默認(rèn)值呢?其實(shí)很簡單默認(rèn)值在擴(kuò)展屬性中保存在一個(gè) 28、的了,原理就是其內(nèi)部有一個(gè)Dictionary 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);
}
}
不過這里還是有一個(gè)小小的技巧的就是OwnerType這個(gè)屬性和AttachOwner方法,默認(rèn)的OwnerType屬性的值是擴(kuò)展對象本身的Type,但是通過 AttachOwner方法我們可以改變這個(gè)屬性從而達(dá)到將不繼承自ExtendObject類型的對象裝飾成E 38、xtendObject
對象的目地。
(3).也就是AttachObject
AttachObject類通過調(diào)用AttachOwner方法使用了這個(gè)技巧,同時(shí)把同樣為ExtendObject的對象的屬性統(tǒng)統(tǒng)都Copy過來.
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
- 溫馨提示:
1: 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
2: 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
3.本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
5. 裝配圖網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024《增值稅法》全文學(xué)習(xí)解讀(規(guī)范增值稅的征收和繳納保護(hù)納稅人的合法權(quán)益)
- 2024《文物保護(hù)法》全文解讀學(xué)習(xí)(加強(qiáng)對文物的保護(hù)促進(jìn)科學(xué)研究工作)
- 銷售技巧培訓(xùn)課件:接近客戶的套路總結(jié)
- 20種成交的銷售話術(shù)和技巧
- 銷售技巧:接近客戶的8種套路
- 銷售套路總結(jié)
- 房產(chǎn)銷售中的常見問題及解決方法
- 銷售技巧:值得默念的成交話術(shù)
- 銷售資料:讓人舒服的35種說話方式
- 汽車銷售績效管理規(guī)范
- 銷售技巧培訓(xùn)課件:絕對成交的銷售話術(shù)
- 頂尖銷售技巧總結(jié)
- 銷售技巧:電話營銷十大定律
- 銷售逼單最好的二十三種技巧
- 銷售最常遇到的10大麻煩