OOP: Encapsulation in C#

This post is based on Chapter 5 of Andrew Troelsen’s “Pro C# 2008 and the .Net Platform” availble from Apress.

So the main aim of encapsulation is to keep things simple and manage the intricasies of an objects task within that object. We want to be able to tell and object to do something, and not have to worry about how it does it. This principle is used extensively throughout the .NET framework, for example when you tell a GridView to DataBind() or you tell a file to Load from a specific path – there is obviously lots going on below the hood, but we don’t have to worry about this, we just read the method description, supply the required data and happily carry on with whatever we are doing.

A second benifit of encapsulation is that we are free to change how a certain task is accomplished within the class or struct, without having to worry about any external code (as long as we maintain our parameters and return type of course).

So what are the building blocks for this? Well first and foremostly this is really a pattern or a practise that you have to aim for in your coding and system designs. I will be writing about OO Design Patterns later in this blog, but basically we are looking at responsiblity and maintaining this within the most relevant class. Taking the above example, it makes sense that all the details about loading a file from disk into memory is encapsulted within the File class.

Access Modifiers

One of the main tools you will use when designing encapsulation are type member access modifiers – so that is keywords used to restrict access to fields, properties, methods, or events declared on a class or struct (as we’re including struct here we will refer to “type members” as opposed to “class members”).

To quickly run through the access modifiers we have:

  • public: no access restrictions here – all classes and even external assemblies can access public class members.
  • private: this is the default for class and struct (type) members. These members can only be accessed from within the owning type.
  • protected: the defining type and any inheriting classes (remember structs do not allow inheritance) can access protected members.
    Using protected methods and fields implies a certain level of trust between the parent and the inheriting class. This is not neccesarily a problem, but some thing you should be aware of. If you want to protect certain data by business rules in the base class, it’s possible to define private fields, with protected get or set methods.  Also you can use the internal keyword to extend this principle at the assembly level.
  • internal: these are in a sense public – but only within the defining assembly.
  • protected internal: this simply combines protected and interal – of course it is possible to inherit from a class defined in another (referenced) assembly – this allows you to stop such inheriting classes from accessing your member(s).

The default access modifiers (if not defined) are private for type members and internal for types.

Desgining Encapsulated Classes (and structs)

First thing you want to do is wrap all accessible members in properties. This allows you to control how these are accessed and perform any validation or cleaning logic you need before anything is done to your class members. Note that in the Intermidiate Language code generated all properties are represented as get_[property_name] and set_[property_name]. Not sure what you will do with that information, but it might come in handy some day I guess.

Note that it is also possible to define properties with a different modifier on the get and set method respectively, basically you override the overall property access modifier within the property just before the get or set block:

	private string _someString;
	public string SomeProperty
	{
		get
		{
			return _someString;
		}

		protected set
		{
			_someString = value;
		}
	}

Also note that you can have static properties. These of course work at the class level, and can be used in a similar way to static constructors to set members that apply globally to all existing and subsequent instances of the type.

Finally – you might want to have a look at the new auto implemented properties in .NET 3.5 – these basically just allow you to skip the trivial get/set blocks and just write empty statements as in the below example. Behind the scenes these are of course implemented in the same way in the CIL – and we end up with our get_ and set_ property members.

	public string AnotherProperty { get; set; }
Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: