CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Patrick Smacchia [MVP C#]


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.



Comments

Jason Meridth said:

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?

# October 3, 2007 11:02 AM

Patrick Smacchia said:

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.

# October 4, 2007 10:24 AM

cmyers said:

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.  

# October 4, 2007 10:44 AM

cmyers said:

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)

# October 4, 2007 10:51 AM

Patrick Smacchia said:

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.

# October 4, 2007 3:14 PM

Patrick Smacchia [MVP C#] said:

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

# November 26, 2007 3:11 PM

Patrick Smacchia [MVP C#] said:

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

# May 11, 2008 4:53 PM

Community Blogs said:

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

# May 12, 2008 3:45 AM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add

About Patrick Smacchia

Patrick Smacchia is a Visual C# MVP involved in software development for over 15 years. After graduating in mathematics and computer science, he has worked on software in a variety of fields including stock exchange, airline ticket reservation system as well as a satellite base station at Alcatel. He's currently a software consultant and trainer on .NET technologies as well as the lead developer of the tool NDepend which provides numerous metrics and caveats on any compiled .NET application. He is the author of Practical .NET2 and C#2, a .NET book conceived from real world experience with 647 compilable code listings. Check out Devlicio.us!

Our Sponsors