2013-02-20 100 views
3

我正在做一個「適配器」基類,它實例化一個私有結構。該結構通過一個抽象的Configure()方法暴露給繼承者,所以他們可以在其上設置屬性。執行標準如下:使用ref返回

public abstract class PaymentAdapter { 

    private PaymentObject p = new PaymentObject(); 

    protected PaymentObject CreditCardPayment { 
     get { return p; } 
    } 

    protected abstract void Configure(PaymentObject payment); 

    public MyResponse ProcessPayment() { 
     // Run the adapter's setup 
     Configure(p); 

     // Charge the customer 
     var chargeResult = p.DoSomething(); 

     return new MyResponse { 
      MyResult = chargeResult 
     }; 
    } 
} 

你們誰善於觀察會看到下面的行需要一些注意:

protected abstract void Configure(PaymentObject payment); 

當一個具體的類中重寫,這個方法(幾乎)給消費者有機會直接修改結構的屬性。這是理想的結果。

我的問題是 - 我應該使用ref參數還是將void更改爲PaymentObject,使消費者自己返回實例?

方法1:

protected abstract PaymentObject Configure(PaymentObject payment); 

方法2:

protected abstract void Configure(ref PaymentObject payment); 

因此,繼承類時,消費者就必須做到以下幾點:

方法1:

public class MyConsumer : PaymentAdapter { 
    #region Overrides of PaymentAdapter 

    protected override PaymentObject Configure(PaymentObject payment) { 
     payment.AProperty = "Something"; 
      return payment; 
    } 

    #endregion 
} 

方法2:

public class MyConsumer : PaymentAdapter { 
    #region Overrides of PaymentAdapter 

    protected override void Configure(ref PaymentObject payment) { 
     payment.AProperty = "Something"; 
    } 

    #endregion 
} 

除了語法上的輕微變化之外,還有其他的區別嗎?這是一個偏好的事情,還是有沒有好處,我不能看到使用一個在另一個?由於代碼略少,我傾向於使用「ref」方法,這與我從方法中專門返回對象的所有年份相反。這對於參考論證來說似乎是一個完美的例子 - 它使消費者的工作稍微容易一些,並且意味着我不會在整個地方設置對象。

+5

在方法2中,您不需要'ref'參數; 'PaymentObject'是一個類,不是一個結構(我假設),因此已經是一個引用類型。 – antonijn 2013-02-20 12:54:45

+0

好吧,讓我們說PaymentObject是一個結構然後:) – Spikeh 2013-02-20 12:57:29

+0

我建議你使用返回方法。沒有實際的需要使用ref,你沒有幾個你想返回的對象。我不會在乎或多或少的2或3行代碼。 – 2013-02-20 12:57:56

回答

2

引用類型默認情況下通過引用傳遞,因此您不必在此處使用ref關鍵字。

如果你的類型是Struct你一定要使用return語句,因爲結構應該是一成不變的(爲什麼?閱讀Why are mutable structs 「evil」?Why are C# structs immutable?答案)

+0

對不起,這個問題的目的是要修改結構,而不是對象。 – Spikeh 2013-02-20 13:03:55

+0

好的,我延長了我的回答。 – MarcinJuraszek 2013-02-20 13:08:27

0

如果你只對實際PaymentObject更改屬性沒有必要爲使用ref。它仍然是被改變的同一個對象。

我建議你

protected abstract void Configure(PaymentObject payment); 

去沒有需要返回的對象,因爲它會改變實際的對象。

+0

OP沒有指定'PaymentObject'是否是引用類型。 – antonijn 2013-02-20 13:02:32

+0

對不起,這個問題的目的是要修改結構,而不是對象。 – Spikeh 2013-02-20 13:04:53

+0

對不起。自從PaymentObject被命名爲...對象我只是假定它是一個對象:( – Evelie 2013-02-20 13:25:41

1

如果PaymentObject是一個結構,那麼方法2會更快,因爲在方法1中,您首先複製PaymentObject的實例,修改該副本並返回該副本的副本。在我做的一個基準測試中(對於一個64字節大的結構體,Linux Mint 14上的Mono),第二種方法的速度是三倍。

然而,第二種方法有一些缺點。在C#中,有一種不成文的規則,你不應該直接改變不屬於有問題的方法或類的結構。這主要與接口的線程和複雜性有關。

所以我會去第一種方法,除非你真的想要性能,並不需要擔心線程的複雜性。

+0

這正是我的想法 - 如果我使用「返回」,我會有效地結束3個結構的副本內存...雖然這是一種更乾淨的方式來做事 我實際上修改PaymentObject上的5到25個屬性之間的任何地方。 – Spikeh 2013-02-20 13:20:29

0

我認爲在這種情況下你應該選擇'ref'參數。因爲使用'ref',您也可以從'CreditCardPayment'屬性中獲得PaymentObject值。但是,如果您返回該對象,那麼它將僅在「ProcessPayment」方法內返回對象,並且您無法從「CreditCardPayment」屬性中獲取實際值。