На самом деле вы можете воспроизвести поведение C ++ const в C # - вам просто нужно сделать это вручную.
Каким бы ни был Foo
, вызывающий может изменить свое состояние только путем вызова методов или установки свойств.
Например, Foo
имеет тип FooClass
:
class FooClass
{
public void MutateMyStateYouBadBoy() { ... }
public string Message
{
get { ... }
set { ... }
}
}
Так что в вашем случае вы рады, что они получили свойство Message
, но не установили его, и вы определенно не рады тому, что они вызывают этот метод.
Итак, определите интерфейс, описывающий, что им разрешено делать:
interface IFooConst
{
public string Message
{
get { ... }
}
}
Мы оставили метод мутации и оставили его только в получателе свойства.
Затем добавьте этот интерфейс в базовый список FooClass
.
Теперь в вашем классе со свойством Foo
у вас есть поле:
private FooClass _foo;
И получатель недвижимости:
public IFooConst Foo
{
get { return _foo; }
}
Это в основном воспроизводит вручную то, что ключевое слово C ++ const
будет делать автоматически. В терминах psuedo-C ++ ссылка типа const Foo &
подобна автоматически сгенерированному типу, который включает в себя только те элементы Foo
, которые были отмечены как const
члены. Если перевести это в некую теоретическую будущую версию C #, вы объявите FooClass
следующим образом:
class FooClass
{
public void MutateMyStateYouBadBoy() { ... }
public string Message
{
get const { ... }
set { ... }
}
}
На самом деле все, что я сделал, это объединил информацию из IFooConst
обратно в FooClass
, пометив одного безопасного члена новым ключевым словом const
. Таким образом, добавление ключевого слова const не добавит много языка, кроме формального подхода к этому шаблону.
Тогда, если у вас была const
ссылка на FooClass
объект:
const FooClass f = GetMeAFooClass();
Вы сможете звонить членам const только по f
.
Обратите внимание, что если определение FooClass
является общедоступным, вызывающий может преобразовать IFooConst
в FooClass
. Но они могут делать это и в C ++ - это называется «отбрасывание const
» и включает специальный оператор под названием const_cast<T>(const T &)
.
.
Существует также проблема, заключающаяся в том, что интерфейсы не очень легко развиваются между версиями вашего продукта. Если третья сторона может реализовать заданный вами интерфейс (который он может сделать, если сможет его увидеть), вы не сможете добавлять новые методы к нему в будущих версиях, не требуя, чтобы другие перекомпилировали их код. Но это проблема, только если вы пишете расширяемую библиотеку для других. Возможно, встроенная функция const
решит эту проблему.