Я бы представлял объект кредитной карты с парой разных интерфейсов. У одного были бы сеттеры, а у другого - сеттеры. Свойство CreditCard класса Order будет только интерфейсом получения.
class CreditCardBase : ICreditCard
{
string Name { get; }
}
interface IWritableCreditCard : ICreditCard
{
string Name { get; set; }
}
class WritableCreditCard : CreditCardBase, IWritableCreditCard {}
class Order
{
private ICreditCard _card = new WritableCreditCard(); //initially...
public ICreditCard Card { get {return _card; } }
void OnComplete(...) { _card = new CreditCardBase(copy from _card); }
}
Во время выполнения приведите свойство «Card» к интерфейсу установщика, чтобы изменить свойства карты. Если состояние заказа теперь находится в состоянии только для чтения, то объект, реализующий CreditCard, был бы заменен реализацией, которая реализует только получатели.
Я не понимаю, как вы могли бы различить во время компиляции, но, по крайней мере, обычные действия были бы безопасными вызовами "только для получателя", и код модификации был бы а) уродлив и прост в обнаружении и б) возвратился null или throw, если выполнено в неправильное время.