You can actually reproduce the behaviour of C++ const in C# - you just have to do it manually.
Whatever Foo
is, the only way the caller can modify its state is by calling methods on it or setting properties.
For example, Foo
is of type FooClass
:
class FooClass
{
public void MutateMyStateYouBadBoy() { ... }
public string Message
{
get { ... }
set { ... }
}
}
So in your case, you're happy for them to get the Message
property, but not set it, and you're definitely not happy about them calling that method.
So define an interface describing what they're allowed to do:
interface IFooConst
{
public string Message
{
get { ... }
}
}
We've left out the mutating method and only left in the getter on the property.
Then add that interface to the base list of FooClass
.
Now in your class with the Foo
property, you have a field:
private FooClass _foo;
And a property getter:
public IFooConst Foo
{
get { return _foo; }
}
This basically reproduces by hand precisely what the C++ const
keyword would do automatically. In psuedo-C++ terms, a reference of type const Foo &
is like an automatically generated type that only includes those members of Foo
that were marked as const
members. Translating this into some theoretical future version of C#, you'd declare FooClass
like this:
class FooClass
{
public void MutateMyStateYouBadBoy() { ... }
public string Message
{
get const { ... }
set { ... }
}
}
Really all I've done is merged the information in IFooConst
back into FooClass
, by tagging the one safe member with a new const
keyword. So in a way, adding a const keyword wouldn't add much to the language besides a formal approach to this pattern.
Then if you had a const
reference to a FooClass
object:
const FooClass f = GetMeAFooClass();
You would only be able to call the const members on f
.
Note that if the FooClass
definition is public, the caller could cast an IFooConst
into a FooClass
. But they can do that in C++ too - it's called "casting away const
" and involves a special operator called const_cast<T>(const T &)
.
There's also the issue of interfaces not being very easy to evolve between versions of your product. If a third party may implement an interface you define (which they are free to do if they can see it), then you can't add new methods to it in future versions without requiring others to recompile their code. But that's only a problem if you are writing an extensible library for others to build on. Maybe a built-in const
feature would solve this problem.