Using the dynamic Keyword in C# to Improve Object Orientation – A Follow-up

Based on some feedback, some clarification is warranted with regard to my previous post titled “Using the dynamic Keyword in C# to Improve Object Orientation”.

As Jarek Kowalski correctly pointed out, the example code that I provided could have used the Visitor pattern instead to get the same result.  My impetus for using the dynamic keyword the way I did was slightly different from how I described my example—which was meant to be easier to read.

I think it’s worthwhile describing the Visitor Pattern.  The Visitor pattern is a pattern used to separate the responsibility of an algorithm from the class that the algorithm should operate upon.  Essentially, a Visitor class is created to contain the algorithm that would be invoked through its Visit method and the classes that the algorithm operates upon some sort of method that accepts a reference to a Visitor object (which would simply invoke the Visit method).  The example that Jarek provided was very similar to:

 	public interface IShapeVisitor 
 	{
 		void Visit(Circle square);
 		void Visit(Rectangle square);
 	}
 
 	public class Circle : Shape 
 	{
 		public override void Accept(IShapeVisitor shapeVisitor)
 		{
 			shapeVisitor.Visit(this);
 		}
 		//... 
 	}
 


And an implementation of IShapeVisitor would be provided like this:



 	public  class  DrawingVisitor  : IShapeVisitor
 	{
 		public  void  Visit(Circle circle)
 		{
 			// draw circle here 
 		}
 		public  void  Visit(Rectangle rectangle)
 		{
 			// draw rectangle here 
 		}
 	}
 
 


In our case, the bodies of Visit methods would call a Draw method contained in another class like a View implementation.  For example:

 	public  class  DrawingVisitor  : IShapeVisitor 
 	{
 		private  IView  view;
 		public  DrawingVisitor(IView  view)
 		{
 			this.view = view;
 		}
 
 		public  void  Visit(Circle  circle)
 		{
 			view.Draw(circle);
 		}
 
 		public  void  Visit(Rectangle  rectangle)
 		{
 			view.Draw(rectangle);
 		}
 	}
 

This of course, adds another level of indirection that allows our target (a Shape implementation) to invoke a virtual method that ends up delegating to the Visitor.  An implementation of Double Dispatch.  This allows objects whose type isn’t known until run-time to properly invoke overloaded methods of another type.

As you can see, this is very powerful but adds a bit more complexity.

Now, in my original scenario (before I wrote the example for the post), I was dealing with invoking particular series of static overloads of System.Convert.  Because I was dealing both with a class outside of my control and dealing with static overloads, the Visitor pattern could not be applied.

Using the dynamic Keyword in C# to Improve Object-Orientation

With polymorphism, object-oriented languages allow “…different data types to be handled using a uniform interface”.  Ad-hoc polymorphism is when you declare multiple methods of the same name but differ by the type of an argument.  For example:


 private  static  void  Draw(Circle  circle)
 {
 	//... 
 }
 private  static  void  Draw(Square  square)
 {
 	//... 
 }
 

These are usually referred to as method overloads or method overloading.  Which Draw method that gets invoked would be decided upon at compile-time based on the type of the parameter passed to it.


This is great, there are many situations where this is useful; but what about situations where you don’t know the exact type of the object until run-time?  Many programmers instinctly lean towards using the GetType method available on all objects in .NET and perform a manual type comparison.  For example:


 public  void  ProcessShape(Shape  shape)
 {
 	Type  type = shape.GetType();
 	if  (type == typeof (Square ))
 	{
 		Draw((Square )shape);
 	}
 	else  if  (type == typeof (Circle ))
 	{
 		Draw((Circle )shape);
 	}
 	//... 
 }
 

There are other variants of this that make it a little harder to detect (and often gets around static code analysis warnings):


 public  void  ProcessShape(Shape  shape)
 {
 	Square  square = shape as  Square ;
 	if  (square != null )
 	{
 		Draw(square);
 		return ;
 	}
 	Circle  circle = shape as  Circle ;
 	if  (circle != null )
 	{
 		Draw(circle);
 		return ;
 	}
 	//... 
 }
 

This code is a problem because we lose the benefits of C#s polymorphism (this code is coupled to Circle and Shape, if either is removed, this code would have to be changed and re-tested.   If another Shape derivative were added, the code would again have to be changed and re-tested).  There are multiple circumstances where this might happen over and above the so-far specious examples above.  For example, deserializing an object from a Stream often results in not knowing the exact type of the object that has been deserialized.  This is common with type hierarchies.  For example:


 private  static  Shape  DeserializeShape(Stream  stream)
 {
 	IFormatter  formatter = new  BinaryFormatter ();
 	return  formatter.Deserialize(stream) as  Shape ;
 }
 

With the above code, we’ve re-hydrated either a Circle of a Square object into a Shape object (and ignored the appropriate checks to make sure a Shape object was loaded).  We’re now unable to use all the other polymorphism features of C#: method overloading won’t work, C# will always only use the overload with the Shape argument and generics suffers from the same problem, it will always resolve to the type parameter of type Shape.  For example, if we try to call one of our two Draw methods with our re-hydrated Shape object:


 			Draw(shape);



…we simply get a CS1502 warning because there is now Draw(Shape shape) method.


 


When programmers simply compare types, they’re admitting that polymorphism has been circumvented and they have to resort to introducing the Conditional Complexity Code Smell or the Switch Statement Code Smell (C# doesn’t support Type in a switch statement, so some programmers go ahead and create a integer type code–or even worse, use String in the switch statement)


So, what’s a programmer to do to keep our code object-oriented and use polymorphism?


Well, if you read the title of this post, you’ve probably figured it out: use the dynamic keyword.  The dynamic keyword bypasses static (compile-time) type checking and performs the type-checking dynamically (at run-time).  So, for us to use our Draw overloads with our Shape object, we simply assign it to a dynamic object and use that object instead.  For example:


 			Shape  shape = DeserializeShape(stream);
 			dynamic  dynShape = shape;
 			Draw(dynShape);

Now the runtime will check to see the actual type of dynShape object and invoke the corresponding Draw overload.


In our example, we’ve used inheritance to derive our two shapes from a single base.  But, given our current use of Circle and Square objects, we don’t need them to inherit from the same base class.  We could simply view these shapes as an Object when we want to use dynamic.  For example:


 private  static  Object  DeserializeShape(Stream  stream)
 {
 	IFormatter  formatter = new  BinaryFormatter ();
 	return  formatter.Deserialize(stream);
 }
 
 			//... 
 			dynamic  shape = DeserializeShape(stream);
 			Draw(shape);
 

With the above, we’d have the same result without deriving both Circle and Square from Shape.


kick it on DotNetKicks.com

Refactoring with Visual Studio 2010

While putting some finishing touches on the book, the publisher has put details about the book on their website.


https://www.packtpub.com/refactoring-with-microsoft-visual-studio-2010/book


From the overview:


Changes to design are an everyday task for many people involved in a software project. Refactoring recognizes this reality and systematizes the distinct process of modifying design and structure without affecting the external behavior of the system. As you consider the benefits of refactoring, you will need this complete guide to steer you through the process of refactoring your code for optimum results.

This book will show you how to make your code base more maintainable by detailing various refactorings. Visual Studio includes some basic refactorings that can be used independently or in conjunction to make complex refactorings easier and more approachable. This book will discuss large-scale code management, which typically calls for refactoring. To do this, we will use enterprise editions of Visual Studio, which incorporate features like Application Performance Explorer and Visual Studio Analyzer. These features make it simple to handle code and prove helpful for refactoring quickly.

This book introduces you to improving a software system’s design through refactoring. It begins with simple refactoring and works its way through complex refactoring. You will learn how to change the design of your software system and how to prioritize refactorings—including how to use various Visual Studio features to focus and prioritize design changes. The book also covers how to ensure quality in the light of seemingly drastic changes to a software system. You will also be able to apply standard established principles and patterns as part of the refactoring effort with the help of this book. You will be able to support your evolving code base by refactoring architectural behavior. As an end result, you will have an adaptable system with improved code readability, maintainability, and navigability.


Scheduled to be available in September.


kick it on DotNetKicks.com

Layers in Visual Studio 2010

Visual Studio 2010 has a new featured called Layer Diagrams.  In the Ultimate edition you can create layer diagrams that model the logical layers in your software system.

What is a Layer?

I’m glad you asked what a layer is.  A layer is a logical grouping of types with similar external assembly dependencies.  Dependencies between layers occur only in one direction from a higher-level layer to a lower-level layer.  I.e. a higher-level layer can use types in a lower-level layer, but not vice versa. A canonical example is the Data Access Layer (or DAL).  The DAL contains all the types that directly use types responsible for data-access.

Using the Layer Diagram

Within the Layer Diagram user interface, it can be unclear what a layer is.  The Layer Diagram is really just a dependency diagram that allows creation of a logical layer that can be linked to physical artefacts.

Creating a layer diagram in Visual Studio Ultimate is easy, select New Diagram from the Architecture menu and the Add New Diagram dialog will be displayed.

vs-arch-new diagram

In the Add New Diagram dialog, select the Layer Diagram entry and enter the name of the layer diagram file.

vs-add new diagram

If your solution does not currently contain a Modeling project, one will be created automatically when you press OK as indicated by “Create a new modelling project…” in the Add to modeling project combo box.

Once the modeling project is created and the new layer diagram is added to that project, you will be presented with the Layer Diagram design surface.  You have many options to creating a layer in the diagram, you can use entries in the toolbox to create layers, dependencies, and comments:

layer diagram toolbox

Or, you can drag artefacts from the Solution Explorer or the Architecture Explorer to create layers in various ways.  Normal dragging of a single artefact onto the design service creates a new layer with a one-to-one mapping (a “link” in Layer Diagrams) from layer to artefact.  This is especially useful for projects from the solution explorer.  It’s not uncommon for logical layers to be implemented as tiers (or physical assemblies).  Or, you can create a one-to-many mapping from layer to artefacts by normal dragging of artefacts onto the design surface.  This is useful when you’re modeling layers but haven’t modeled them as tiers and multiple layers exist in a single assembly or project.  Via the Architecture Explorer and the Solution Explorer you can link assemblies (projects), types, namespaces, methods, properties, fields, and files to a layer.

Regardless of how the layer was created on the diagram, you can add links to it by dragging them from the Solution Explorer or Architecture Explorer onto a layer to create a link to it.  Oddly, although you can link to classes and namespaces, you can’t drag classes or namespaces from the Class View onto the Layer Diagram design surface.

The following diagram was created by dragging three projects from the Solution Explorer to the design surface and invoking Generate Dependencies on all three of the created layers:

Layer Diagram

Once a layer model has been defined, you can then ask Visual Studio to validate the solution against that logical architecture. Within the layer diagram you can have a one-to-one mapping of layer to links, or a one-to-many mapping.  i.e. a layer can consist of one or more links (at least in terms of validation—you can have zero links in a layer if you want; but then VS has no information with which to validate anything). If, for whatever reason, the current solution doesn’t follow the logical architecture, an error will result.   You can also configure the solution to automatically validate the solution against the layer diagram during a build.  This build-time validate can occur in both the Ultimate and Premiums editions of Visual Studio 2010.

Why is it really just a Dependency Diagram?

Another really good question!  The Layer Diagram is really just a dependency diagram because there’s no inherent recognition for layer levels.  Because there’s no way of defining a level, there’s no way to group layers within a specific level.  Layer diagrams also allow bi-directional dependencies; a definite no-no with two layers at different levels.  It’s also really difficult to really enforce only a particular layer having references to particular external references.  You can declare forbidden namespaces for a particular layer, but it’s a cumbersome method of enforcing references to particular components only occur in a certain layer.  For example, if I had a DAL and I wanted to make sure only data-access occurred in that layer, I could add “System.Data” to the Forbidden Namespace Dependencies for all layers expect the DAL and incur an error with Layer Validation should any types from System.Data be used in any of those Layers.  But, things like DataGridView in Windows Forms are used primarily with types in System.Data so it becomes difficult to manage these dependencies.