C# 使用ref-over-return

C# 使用ref-over-return,c#,reference,abstract-class,C#,Reference,Abstract Class,我正在创建一个“适配器”基类来实例化一个私有结构。该结构通过抽象Configure()方法向继承者公开,因此继承者可以对其设置属性。执行情况如下: public abstract class PaymentAdapter { private PaymentObject p = new PaymentObject(); protected PaymentObject CreditCardPayment { get { return p; } }

我正在创建一个“适配器”基类来实例化一个私有结构。该结构通过抽象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);
public class MyConsumer : PaymentAdapter {
    #region Overrides of PaymentAdapter

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

    #endregion
}
方法2:

protected abstract void Configure(ref PaymentObject payment);
public class MyConsumer : PaymentAdapter {
    #region Overrides of PaymentAdapter

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

    #endregion
}
因此,在继承类时,使用者必须执行以下操作:

方法1:

protected abstract PaymentObject Configure(PaymentObject payment);
public class MyConsumer : PaymentAdapter {
    #region Overrides of PaymentAdapter

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

    #endregion
}
方法2:

protected abstract void Configure(ref PaymentObject payment);
public class MyConsumer : PaymentAdapter {
    #region Overrides of PaymentAdapter

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

    #endregion
}
除了语法上的细微变化外,还有什么不同吗?这是一种偏好,还是我看不到使用其中一种的好处


由于代码稍少,我倾向于使用“ref”方法,这与我多年来只从方法返回对象的做法相反。对于ref参数来说,这似乎是一个完美的例子-它使使用者的工作稍微容易一些,并且意味着我没有到处设置对象。

默认情况下引用类型是按引用传递的,因此您不必在此处使用
ref
关键字


如果您的类型是
Struct
,您一定要使用
return
语句,因为结构应该是不可变的(为什么?请阅读和的答案)

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

我建议你和我一起去

protected abstract void Configure(PaymentObject payment);

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

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

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


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

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

在方法2中,您不需要
ref
参数
PaymentObject
是一个类,而不是一个结构(我猜),因此已经是一个引用类型。好的,假设PaymentObject是一个结构:)我建议您使用return方法。实际上不需要使用ref,您不需要返回多个对象。我不在乎2行或3行代码。@bash.d但如果它是一个大结构,可能会导致性能问题(首先将对象复制到参数,然后将其复制到返回类型)。@Antonijn True,但大是多大?如果这就是问题所在,我同意,除此之外,您应该更喜欢return而不是ref。OP没有指定
PaymentObject
是否是引用类型。对不起,这个问题是关于修改结构,而不是对象。哦,对不起。。由于PaymentObject被命名为。。。对象我只是假设它是一个对象:(对不起,这个问题是关于修改结构,而不是对象。这正是我所想的-如果我使用“return”,我将有效地在内存中创建结构的3个副本…尽管这是一种更干净的方法。实际上,我正在修改PaymentObject上5到25个属性之间的任意位置。