前言
本文已更新至http://m.survivalescaperooms.com/aehyok/p/3624579.html。本文主要學(xué)習(xí)記錄以下內(nèi)容:
建議13、為類(lèi)型輸出格式化字符串
建議14、正確實(shí)現(xiàn)淺拷貝和深拷貝
建議15、使用dynamic來(lái)簡(jiǎn)化反射實(shí)現(xiàn)
建議13、為類(lèi)型輸出格式化字符串
有兩種方法可以為類(lèi)型提供格式化的字符串輸出。
一種是意識(shí)到類(lèi)型會(huì)產(chǎn)生格式化字符串輸出,于是讓類(lèi)型繼承接口IFormattable。這對(duì)類(lèi)型來(lái)說(shuō),是一種主動(dòng)實(shí)現(xiàn)的方式,要求開(kāi)發(fā)者可以預(yù)見(jiàn)類(lèi)型在格式化方面的要求。
更多的時(shí)候,類(lèi)型的使用者需為類(lèi)型自定義格式化器,這就是第二種方法,也是最靈活多變的方法,可以根據(jù)需求的變化為類(lèi)型提供多個(gè)格式化器。
下面我們就來(lái)看一下這兩種方式的實(shí)現(xiàn)。
最簡(jiǎn)單的字符串輸出是為類(lèi)型重寫(xiě)ToString()方法,如果沒(méi)有為類(lèi)型重寫(xiě)該方法,默認(rèn)會(huì)調(diào)用Ojbect的ToString方法,它會(huì)返回當(dāng)前類(lèi)型的類(lèi)型名稱(chēng)。但即使是重寫(xiě)了ToString()方法,提供的字符串輸出也是非常單一的,而通過(guò)實(shí)現(xiàn)IFormattable接口的ToString()方法,可以讓類(lèi)型根據(jù)用戶(hù)的輸入而格式化輸出。
下面我們來(lái)看一個(gè)簡(jiǎn)單的小例子:
public class Person:IFormattable { public string IDCode { get; set; } public string FirstName { get; set; } public string LastName { get; set; } /// <summary> /// 實(shí)現(xiàn)接口Iformattable的方法ToString /// </summary> /// <param name="format"></param> /// <param name="format調(diào)用代碼如下所示:
static void Main(string[] args) { Person person = new Person() { FirstName="Kris",LastName="aehyok"}; Console.WriteLine(person); Console.WriteLine(person.ToString("Ch",null)); Console.WriteLine(person.ToString("Eg", null)); Console.ReadLine(); }調(diào)用執(zhí)行結(jié)果如下:

下面我們來(lái)繼續(xù)介紹第二實(shí)現(xiàn)方式——格式化器。如果類(lèi)型本身沒(méi)有提供格式化的功能,那么格式化器就可以派上用場(chǎng)了。格式化器的好處就是可以根據(jù)需求的變化,隨時(shí)增加或者修改它。
接下來(lái)我們繼續(xù)來(lái)看另外的一個(gè)小例子:
首先定義一個(gè)實(shí)體類(lèi)Person:
public class Person { public string IDCode { get; set; } public string FirstName { get; set; } public string LastName { get; set; } }一個(gè)典型的格式化器應(yīng)該繼承IFormatProvider和ICustomerFormatter,看代碼:
public class PersonFomatter:IFormatProvider,ICustomFormatter { #region IFormatProvider成員 public object GetFormat(Type formatType) { if (formatType == typeof(ICustomFormatter)) { return this; } else { return null; } } #endregion #region ICustomFormatter成員 public string Format(string format, object arg, IFormatProvider formatProvider) { Person person = arg as Person; if (person == null) { return string.Empty; } switch (format) { case"Ch": return string.Format("{0} {1}",person.LastName,person.FirstName); case"": return string.Format("{0} {1}",person.FirstName,person.LastName); case"CHM": return string.Format("{0} {1}:{2}", person.LastName, person.FirstName, person.IDCode); default: return string.Format("{0} {1}", person.LastName, person.FirstName); } } #endregion }調(diào)用代碼如下:
class Program { static void Main(string[] args) { Person person = new Person() { FirstName="Kris", LastName="aehyok", IDCode="ID000001"}; Console.WriteLine(person.ToString()); PersonFomatter pFomatter = new PersonFomatter(); Console.WriteLine(pFomatter.Format("Ch", person, null)); Console.WriteLine(pFomatter.Format("Eg", person, null)); Console.WriteLine(pFomatter.Format("CHM", person, null)); Console.ReadLine(); } }調(diào)用執(zhí)行結(jié)果如下:

其實(shí)還有另外一種變通的形式,就是將這兩種方式合并一起使用的過(guò)程,下面來(lái)看一下具體的實(shí)現(xiàn)代碼:
public class Person:IFormattable { public string IDCode { get; set; } public string FirstName { get; set; } public string LastName { get; set; } /// <summary> /// 實(shí)現(xiàn)接口Iformattable的方法ToString /// </summary> /// <param name="format"></param> /// <param name="formatProvider"></param> /// <returns></returns> public string ToString(string format, IFormatProvider formatProvider) { switch (format) { case"Ch": return this.ToString(); case"Eg": return string.Format("{0}{1}", this.FirstName, this.LastName); default: //return this.ToString(); ICustomFormatter customerFormatter = formatProvider as ICustomFormatter; if (formatProvider == null) { return this.ToString(); } return customerFormatter.Format(format, this, null); } } ///重寫(xiě)Object的方法ToString() public override string ToString() { return string.Format("{0}{1}",this.LastName,this.FirstName); } }PersonFomatter自定義格式化器的代碼并沒(méi)有發(fā)生任何的改變。調(diào)用代碼如下:
static void Main(string[] args) { Person person = new Person() { FirstName="Kris", LastName="aehyok", IDCode="ID000001"}; Console.WriteLine(person.ToString()); PersonFomatter pFomatter = new PersonFomatter(); Console.WriteLine(pFomatter.Format("Ch", person, null)); Console.WriteLine(pFomatter.Format("Eg", person, null)); Console.WriteLine(pFomatter.Format("CHM", person, null)); Console.WriteLine(person.ToString("Ch",pFomatter)); Console.WriteLine(person.ToString("Eg", pFomatter)); Console.WriteLine(person.ToString("CHM", pFomatter)); Console.ReadLine(); }調(diào)用執(zhí)行結(jié)果如下所示:

建議14、正確實(shí)現(xiàn)淺拷貝和深拷貝
為對(duì)象創(chuàng)建副本的技術(shù)成為拷貝(也叫克隆)。我們將拷貝分為淺拷貝和深拷貝。
淺拷貝 將對(duì)象中的所有字段復(fù)制到新的對(duì)象(副本)中。其中,值類(lèi)型字段的值被復(fù)制到副本中后,在副本中的修改不會(huì)影響到源對(duì)象對(duì)應(yīng)的值。而引用類(lèi)型的字段被復(fù)制到副本中的是引用類(lèi)型的引用,而不是引用的對(duì)象,在副本中對(duì)引用類(lèi)型的字段值做修改會(huì)影響到源對(duì)象本身。
深拷貝同樣,將對(duì)象中的所有字段復(fù)制到新的對(duì)象中。不過(guò)無(wú)論是對(duì)象的值類(lèi)型字段,還是引用類(lèi)型字段,都會(huì)被重新創(chuàng)建并賦值,對(duì)于副本的修改,不會(huì)影響到源對(duì)象本身。
無(wú)論是淺拷貝還是深拷貝,微軟都建議用類(lèi)型繼承ICloneable接口的方式明確告訴調(diào)用者:該類(lèi)型可以被拷貝。當(dāng)然,ICloneable接口只提供了一個(gè)聲明為Clone的方法,我們可根據(jù)需求在Clone方法內(nèi)實(shí)現(xiàn)淺拷貝或深拷貝。一個(gè)簡(jiǎn)答的淺拷貝的實(shí)現(xiàn)代碼如下所示:
首先定義實(shí)體類(lèi):
public class Employee:ICloneable { public string IDCode { get; set; } public int Age { get; set; } public Department Department { get; set; } #region OCloneable成員 public object Clone() { return this.MemberwiseClone(); } #endregion } public class Department { public string Name{get;set;} public override string ToString() { return this.Name; } }然后進(jìn)行調(diào)用代碼如下:
static void Main(string[] args) { Employee Niki = new Employee() { IDCode = "IDaehyok", Age = 25, Department = new Department() { Name="Depart1" } }; Employee Kris = Niki.Clone() as Employee; Console.WriteLine(string.Format("IDCode:{0}/tAge:{1}/tDepartment:{2}", Kris.IDCode, Kris.Age, Kris.Department)); ///開(kāi)始改變Niki的值
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注