我正在创建一个实例化私有结构的“适配器”基类。结构通过抽象的Configure()方法向继承者公开,因此可以在其上设置属性。实施如下:
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”方法,这与我多年来从方法中专门返回对象相反。对于ref参数来说,这似乎是一个完美的例子 - 它使得消费者的工作稍微容易一些,并且意味着我不会在整个地方设置对象。
答案 0 :(得分:2)
默认情况下,参考类型通过引用传递,因此您不必在此处使用ref
关键字。
如果你的类型是Struct
,你肯定应该使用return
语句,因为结构应该是不可变的(为什么?阅读Why are mutable structs “evil”?和Why are C# structs immutable?的答案)
答案 1 :(得分:1)
如果PaymentObject
是结构,则方法2会更快,因为在方法1中,您首先复制PaymentObject
的实例,修改该副本,然后返回该副本的副本。在我做的基准测试中(对于一个64字节大的结构,Linux Mint 14上的Mono),第二种方法的速度提高了三倍。
然而,第二种方法存在一些缺点。在C#中,存在一种不成文的规则,您不应该直接改变不属于该方法或类的结构。这主要与接口的线程和复杂性有关。
所以我会选择第一种方法,除非你真的想要性能并且不需要担心线程的复杂性。
答案 2 :(得分:0)
如果您只更改实际PaymentObject的属性,则无需使用ref。它仍然是被改变的同一个对象。
我建议你一起去
protected abstract void Configure(PaymentObject payment);
不需要返回对象,因为它是将要更改的实际对象。
答案 3 :(得分:0)
我认为在这种情况下你应该选择'ref'参数。因为使用'ref',您也可以从'CreditCardPayment'属性获取PaymentObject值。但是如果你返回对象然后它将仅在'ProcessPayment'方法内返回对象,你无法从'CreditCardPayment'属性中获得实际值。