如果我們在進行設計時,需要針對一個方法返回多個結果,通常情況下,我們會使用ref或者out參數。同時,我們還是使用泛型元組來返回多個不相關的值。
我們來看下面的代碼,首先定義一個具有繼承關係的結構。
代碼
1 publicclass Person
2 {
3 privatereadonlystring m_strName;
4 publicstring Name
5 {
6 get { return m_strName; }
7 }
8
9 public Person(string name)
10 {
11 m_strName = name;
12 }
13
14 publicoverridestring ToString()
15 {
16 returnstring.Format("Name:{0}", m_strName);
17 }
18 }
19
20 publicclass Employee : Person
21 {
22 privatereadonly Decimal m_deSalary;
23 public Decimal Salary
24 {
25 get { return m_deSalary; }
26 }
27
28 public Employee(string name, decimal salary)
29 : base(name)
30 {
31 m_deSalary = salary;
32 }
33
34 publicoverridestring ToString()
35 {
36 returnstring.Format("Name:{0}, Salary:{1}", base.Name, m_deSalary);
37 }
38 }
下面是測試代碼。
代碼
1 privatestaticvoid Test()
2 {
3 Employee emp =new Employee("Wing", 1000);
4 ChangeName(ref emp, "UnKnown", 2000);
5
6 Person person =new Person("Wing");
7 ChangeName(ref person, "UnKnown");
8 }
9
10 privatestaticvoid ChangeName(ref Employee emp, string newName, Decimal newSalary)
11 {
12 Console.WriteLine(emp);
13 emp =new Employee(newName, newSalary);
14 Console.WriteLine(emp);
15 }
16
17 privatestaticvoid ChangeName(ref Person person, string newName)
18 {
19 Console.WriteLine(person);
20 person =new Person(newName);
21 Console.WriteLine(person);
22 }
我們來看一下使用ref和out時的限制,首先,使用ref參數,很難建立不可變的對象;其次,使用ref參數,很難實現多態,因為ref參數不支援隱式類型轉換。例如上面代碼中,我們需要定義兩個ChangName方法,針對ChangName(Person person)時,傳入Employee類型的對象,否則,就會報編譯錯誤。
其實ref參數和傳回值的區別也在此,方法的傳回值是可以支援隱式類型轉換的,可以將傳回值設定為父類型,然後在實際運行時,返回子類型。
那麼如何避免使用ref參數呢,我們可以使用元組,即Tuple。
我們可以看以下的代碼。
1 private static Tuple<string, Decimal> GetEmpInfo(Employee emp)
2 {
3 return new Tuple<string, Decimal>(emp.Name, emp.Salary);
4 }
或許上面的代碼只是重新調整了一下方法的簽名,但是當你逐漸熟悉使用函數式編程結構時,你就會發現這個技術的重要性。接受out或者ref參數的方法無法與其他方法良好的組合在一起,而返回單一值(無論多複雜)的方法則能很好的進行組合。
ref和out參數表明方法中可以建立出符合宣告類型的對象,多態表明衍生類別總是可以代替基類。不過當方法中需要建立出傳回值對象時,上述說法還包含了一些新的含義。當調用代碼期待基類對象時,很多情況下方法中都會建立出衍生類別型對象。總的來說,上述兩條規則意味著,out和ref參數無法真正的使用到多態,若是改為使用泛型元組返回多個值,那麼你的演算法邏輯會更便於使用。