There is one interesting
detail of modern OOP language (C#, Java, VB.NET, C++…) that often developers
are not aware of: the ‘private encapsulation’ applies at class level and not at
object level. For example, in the following program, we can see that the object
foo1 is able to change the private
state of the object foo2.
class Foo
{
private int m_Field = 0;
internal void UpdateField(Foo
foo) {
foo.m_Field = 1;
}
static void Main() {
Foo
foo1 = new Foo();
Foo
foo2 = new Foo();
foo1.UpdateField(foo2);
}
}
To avoid potential
corrupted state, we often want to encapsulate our fields at object level.
Thanks to the IsDirectlyWritingField
CQL condition, you can restrict the writing access to m_Field to a single property setter. By using the NDepend.CQL.CQLConstraint attribute
(found in $NDepend Install Dir$\Lib\NDepend.CQL.dll),
you can tag the declaration of m_Field
directly with such CQL constraint. Then, our example can be rewritten like this:
using NDepend.CQL;
class Foo
{
[CQLConstraint(@"//
<Name>Encapsulate m_Field state at object level</Name>
WARN IF Count > 0 IN SELECT METHODS WHERE
IsDirectlyWritingField ""Foo.m_Field""
AND !FullNameIs ""Foo.set_Field(Int32)""
")]
private int m_Field = 0;
private int Field { set {
m_Field = value; } }
internal void UpdateField(Foo
foo) {
foo.Field = 1;
// 'foo.m_Field
= 1;' would provoke a CQL constraint warning.
}
static void Main() {
Foo
foo1 = new Foo();
Foo
foo2 = new Foo();
foo1.UpdateField(foo2);
}
}
This way, we will be
automatically warned by the CQL constraint as soon as another method than the Field property setter assigns directly m_Field.
Update: Jason asked below why this is useful to encapsulate the access to a field. I admit that I find this possibility so useful that I didn't take the time to explain the 'why' properly.
A very common need is to be able to track at debugging time all writing access to a field. This way you can figure out why and when it is assigned to the invalid state you noticed. By encapsulating your field this way, you just have to put a single breakpoint to achieve this (instead of having to put N breakpoints at th N places where your field get assigned). Unfortunatly, the debugger don't provide such facility yet (I remember that I have read somewhere that it is a feature hard to provide because of all underlying CLR optimizations).
It can also be useful to intercept all assignement to your field to do something special, such as logging, transforming the value, counting the number of writing etc...
A very common need for object encapsulation (not handled by the
VisualStudio debugger), is to be able to track at debugging time all
writing access to a field because you figured out that it ends up with
an invalid state.