使用ref over return

时间:2013-02-20 12:52:21

标签: c# reference abstract-class

我正在创建一个实例化私有结构的“适配器”基类。结构通过抽象的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参数来说,这似乎是一个完美的例子 - 它使得消费者的工作稍微容易一些,并且意味着我不会在整个地方设置对象。

4 个答案:

答案 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'属性中获得实际值。

相关问题