3

我正在创建一个实例化私有结构的“适配器”基类。该结构通过抽象的 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,让消费者自己返回一个实例?

方法一:

protected abstract PaymentObject Configure(PaymentObject payment);

方法二:

protected abstract void Configure(ref PaymentObject payment);

因此,在继承类时,消费者必须执行以下操作:

方法一:

public class MyConsumer : PaymentAdapter {
    #region Overrides of PaymentAdapter

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

    #endregion
}

方法二:

public class MyConsumer : PaymentAdapter {
    #region Overrides of PaymentAdapter

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

    #endregion
}

除了语法上的细微变化之外,还有其他区别吗?这是一种偏好,还是我看不到使用其中一种的好处?

由于代码略少,我倾向于使用“ref”方法,这与我多年来专门从方法返回对象相反。这似乎是 ref 参数的完美案例 - 它使消费者的工作稍微容易一些,并且意味着我不会到处设置对象。

4

4 回答 4

2

引用类型默认是通过引用传递的,所以这里不必使用ref关键字。

如果您的类型是 aStruct您绝对应该使用return语句,因为结构应该是不可变的(为什么?阅读为什么可变结构“邪恶”?以及为什么 C# 结构不可变?

于 2013-02-20T12:56:35.813 回答
1

如果PaymentObject是结构,那么方法 2 会更快,因为在方法 1 中,您首先复制 的实例PaymentObject,修改该副本,然后返回该副本的副本。在我做的一个基准测试中(对于 64 字节大的结构,Linux Mint 14 上的 Mono),第二种方法的速度快了三倍。

然而,第二种方法有一些缺点。在 C# 中,有一条不成文的规则,您不应该直接改变不属于相关方法或类的结构。这主要与线程和有关接口的复杂性有关。

所以我会选择第一种方法,除非你真的想要性能并且不需要担心线程的复杂性。

于 2013-02-20T13:14:26.990 回答
0

如果您只更改实际 PaymentObject 的属性,则无需使用 ref。它仍然是被改变的同一个对象。

我建议你去

protected abstract void Configure(PaymentObject payment);

不需要返回对象,因为它是将要更改的实际对象。

于 2013-02-20T12:59:24.890 回答
0

我认为在这种情况下你应该选择 'ref' 参数。因为使用“ref”,您也可以从“CreditCardPayment”属性中获取 PaymentObject 值。但是,如果您返回对象,那么它将仅在“ProcessPayment”方法中返回该对象,并且您无法从“CreditCardPayment”属性中获取实际值。

于 2013-02-20T13:49:00.453 回答