Patrick Smacchia [MVP C#]

Sponsors

The Lounge

Wicked Cool Jobs

News

  • NDepend v3 is fully integrated in Visual Studio, and is now available for download! Software dependencies visualization, 82 .NET software metrics, continuous rule validations, assembly version diff, declarative code queries and more ! http://ndepend.com

Advertisement

Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
Encapsulate your Fields at object level

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.


Posted Wed, Oct 3 2007 11:10 AM by Patrick Smacchia

[Advertisement]

Comments

Jason Meridth wrote re: Encapsulate your Fields at object level
on Wed, Oct 3 2007 11:02 AM

What prompted this?  When would you ever need this?

Also you've lost ReSharper rename power.  The IsDirectlyWritingField item takes a string, so if you change the name with ReSharper (or other tools) it will be disconnected.  Also same problem with the type.

Do you get a compile-time warning/error if the attribute is disconnected from the property in any way?

Patrick Smacchia wrote re: Encapsulate your Fields at object level
on Thu, Oct 4 2007 10:24 AM

You need this everytime you want to ensure a stronger encapsulation of a field.

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.

You can also imagine that you wish to do something each time you access the field, such as a transformation of the value or counting the number of access, or logging etc...

If the field get disconnected, the NDepend compiler cannot retrieve it and emit an error. So yes, you get warned if the field name get out of sync.

cmyers wrote re: Encapsulate your Fields at object level
on Thu, Oct 4 2007 10:44 AM

Without knowing a lot about NDepend and CQL, a neat feature might be to have the CQL constraint language be able to reference the attributed element.

So instead of having an attribute on m_Field and then again having to reference "m_Field" in the CQL, why not have something like:

"IsDirectlyWritingField ::referencedField"

That way you still retain renaming ability without sacrificing constraints.  

cmyers wrote re: Encapsulate your Fields at object level
on Thu, Oct 4 2007 10:51 AM

Also, what is the reasoning for having something like CQLConstraint actually in the code?  Maybe I'm a purist, but I hate to have things that aren't directly related to the functioning of the code cluttering up the visual flow of the code.

It seems that CQLConstraints would be better defined in an external file and run as a separate build step (like unit tests, FxCop, etc)

Patrick Smacchia wrote re: Encapsulate your Fields at object level
on Thu, Oct 4 2007 3:14 PM

Your idea of

"IsDirectlyWritingField ::referencedField"

sounds good, we take note.

CQL queries and constraints can be written both in the code or in a separate NDepend project.

Personnally, I like to have CQL queries inside my code to make

the underlying intention explicit while reading at the code. I don't have to have the bodies of my method cluttered though, but this is not the case here.

Patrick Smacchia [MVP C#] wrote Keep your code structure clean
on Mon, Nov 26 2007 3:11 PM

As an architect or a lead developer responsible for the structure of a code base, you spend time creating

Patrick Smacchia [MVP C#] wrote Write Active Conventions on your Code Base
on Sun, May 11 2008 4:53 PM

Recently, both Glenn Block and Ayende wrote about how to define some sort of active conventions about

Community Blogs wrote Write Active Conventions on your Code Base
on Mon, May 12 2008 3:45 AM

Recently, both Glenn Block and Ayende wrote about how to define some sort of active conventions about

Add a Comment

(required)  
(optional)
(required)  
Remember Me?
Devlicio.us