Click here to Skip to main content
15,887,135 members
Articles / Programming Languages / C#
Tip/Trick

Why Private C# Fields are Not as Private as you Thought

Rate me:
Please Sign up or sign in to vote.
1.71/5 (9 votes)
3 Feb 2016CPOL4 min read 10.7K   6   6
Private fields are not accessible outside the class. It’s C# 101 right? As it turns out, it may not be quite as simple as that.

Why private variables are not as private as you thought

Introduction

Private fields are not accessible outside the class. It’s C# 101 right?

Which means this code should not work…

C#
public class Example
{
 private string _someValue;
 public void DoSomething(Example otherObject)
 {
  _someValue = otherObject._someValue; // What!? You can't access a private variable
                   // from another object! Can you?
 }
}

But surprisingly… it does.

As it turns out…

Private variables are accessible from other objects of the same type. When you stop and think about it, it’s not as mad as it first seems. Why do we make a variable private? We do it to encapsulate the state of an object. We also do it to maintain control over the state of the object.

A simple example could be if we were modeling a container with a limited capacity – like a box of chocolates. We could model this as follows:

C#
public class Chocolate
{
 public string Name { get; set; }
}

public class ChocolateBox
{
 public List<Chocolate> Chocolates { get; set; }

 public bool IsValid()
 {
   return Chocolates.Count > -1 && Chocolates.Count < 11;
 }
}

Can You Spot The Problem Here?

Even though we have an IsValid method, it’s still possible to add more than the maximum number of chocolates to the box (not that the customer would actually mind). To prevent this, we can encapsulate the box. Then provide methods which enforce our constraints. A nice added extra is that we no longer need the IsValid method.

C#
 public class Chocolate
 {
  public string Name { get; set; }
 }

public class ChocolateBox
{
 private List<Chocolate> _chocolates;

 public void AddChocolate(Chocolate chocolate)
 {
  if(_chocolates == null) _chocolates = new List<Chocolate>();
  if(_chocolates.Count > 10) throw new Exception("No more space");
  _chocolates.Add(chocolate);
 }

 // Other methods removed for brevity
}

The assumption here is…

You cannot expect developers who are building other parts of the system to know how your thing (box in this case) works. Good tests, whether they be unit or integration will help here. The real value here is you can avoid misunderstandings in your code by making the implicit, explicit.

But if the developer is working within the class, then they should know how the class works. You can then trust them to change the internal state – even of other classes of the same type!

I’m sure there are other good reasons why this quirk exists (if you know one, add it to the comments). But I want to highlight one use which I’ve found particularly handy.

Access to Private Variables is Handy When Building Value Objects (VO)

One of the tactical patterns in Domain Driven Design is Value Objects (VO). By the way, you don’t need to be doing DDD to use it. It’s defining feature is that it’s equitable by its value rather than by id.

A common example is a string. If I create two strings with the same characters in the same order and the same case, then they are equal to each other by value.

Another example could be a ‘telephone number’ in a CRM. One number is equal to another by value. Unless you happen to be writing software for a telephone company, in which case the telephone number could potentially be the customer id and therefore not a VO.

More often than not, a VO is immutable. That is, once it’s created, you can’t change its value. This is the case for our string example. When you ‘change’ a string, you are actually creating a new object.

Back to the point. Why is it helpful to be immutable?

I can think of 4 reasons:

  • It’s much easier to test an object which can’t change.
  • It’s easier to parallelise an immutable object.
  • It’s easier to ensure it is always in a valid state.
  • You don’t need to keep track of many ids in your application *

* is probably the biggest reason.

An Example Value Object

To illustrate a value object, let's model a fluid container – otherwise known in our domain as a cup. Each cup has a maximum capacity of 1l. We can decant the content of 1 cup into another*. Any liquid over the max volume is lost. A cup is considered equal to another cup depending on the volume of liquid it contains.
* from a code perspective, this results in another instance of cup.

Let’s start with some tests…
How do we construct a cup? Because we want to make our cup immutable, let’s pass in the current volume of liquid into the constructor. So our first rather simplistic test could be to ensure we can construct a cup with a volume of liquid.

C#
[Test]
public void Constructor_ValidVolume_ObjectIsNotNull()
{
 var cup = new Cup(0.5m);
 Assert.NotNull(cup);
}

Now let’s ensure we cannot create a cup containing an invalid volume, e.g. more than a litre or less than 0 litres.

C#
[TestCase(-0.1)]
[TestCase(1.1)]
public void Constructor_InvalidVolumes_ThrowsException(decimal invalidVolume)
{
 ArgumentOutOfRangeException expected = new ArgumentOutOfRangeException("volume");
 ArgumentOutOfRangeException actual = null;
 try
 {
  var cup = new Cup(invalidVolume);
 }
 catch (ArgumentOutOfRangeException ex)
 {
  actual = ex;
 }

 Assert.AreEqual(expected.ParamName, actual.ParamName);
}

Now we can get to the interesting part. How do we ensure they are equal? This is where we can take advantage of the access to private variables.

C#
[Test]
public void Equals_TwoEqualCups_AreEqual()
{
    var cup1 = new Cup(0.5m);
    var cup2 = new Cup(0.5m);
    Assert.AreEqual(cup1, cup2);
}

I’ll leave the ‘Decant’ method as an exercise for you. Interesting question though, what happens to the cup when you decant the liquid out of it? It is after all immutable. :)

Conclusion

Value Objects are a useful construct in Domain Driven Design. When overriding the equals method, you can take advantage of this ‘quirk’ in C#. The quirk is you can access private variables of another class of the same type.

Original article posted at: http://danielwhittaker.me/2015/10/28/why-private-c-variables-are-not-as-private-as-you-thought/

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
United Kingdom United Kingdom
I remember learning to code on a ZX spectrum - you know, the one with the little rubber keys. Man that makes me feel old! I blog about Domain Driven Design and CQRS, Event Sourcing in particular. So do take a look at my blog if you're interested in that area of development. You can find it here at: http://danielwhittaker.me

Comments and Discussions

 
QuestionNo, this is how you do it Pin
#realJSOP4-Feb-16 4:13
mve#realJSOP4-Feb-16 4:13 
AnswerRe: No, this is how you do it Pin
Codescribler4-Feb-16 4:48
Codescribler4-Feb-16 4:48 
GeneralPoor premise Pin
PIEBALDconsult3-Feb-16 17:36
mvePIEBALDconsult3-Feb-16 17:36 
GeneralRe: Poor premise Pin
format C: /U4-Feb-16 8:54
format C: /U4-Feb-16 8:54 
GeneralRe: Poor premise Pin
PIEBALDconsult4-Feb-16 11:50
mvePIEBALDconsult4-Feb-16 11:50 
QuestionNo surprise Pin
bling3-Feb-16 15:37
bling3-Feb-16 15:37 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.