When we chatted about Visual Studio architecture tooling in Ranger chalk talk sessions today and especially when I was watching Suhail demonstrate the use of the architecture tooling, I started think about what circular references really mean. Looking at the enormous diagrams generated when analyzing the PetShop or Tailspin sample applications the actual code and the analysis results seem to get lost in all the noise.

I decided to write some simple code, defining classes in four namespaces and creating instances where a class method calls another class method, which in turn calls the original class method. Take note of ClassA2.Test() and ClassB3.Test() …

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5:  
   6: namespace ClassLibraryDemoA
   7: {
   8:     public class ClassA1
   9:     {
  10:         public void Test(int iValue)
  11:         {
  12:             ClassA2 classTwo = new ClassA2();
  13:             classTwo.Test(iValue);
  14:             System.Console.WriteLine(iValue);
  15:         }
  16:     }
  17:     
  18:     public class ClassA2
  19:     {
  20:         public void Test(int iValue)
  21:         {
  22:             ClassA1 classOne = new ClassA1();
  23:             classOne.Test(iValue); 
  24:             ClassA3 classThree = new ClassA3();
  25:             classThree.Test(iValue);
  26:             ClassLibraryDemoD.ClassD1 classFour = new ClassLibraryDemoD.ClassD1();
  27:             classFour.Test(iValue); 
  28:             System.Console.WriteLine(iValue);
  29:         }
  30:     }
  31:  
  32:     public class ClassA3
  33:     {
  34:         public void Test(int iValue)
  35:         {
  36:             ClassLibraryDemoB.ClassB3 classThree = new ClassLibraryDemoB.ClassB3();
  37:             classThree.Test(iValue);
  38:             System.Console.WriteLine(iValue);
  39:         }
  40:     }
  41: }
  42:  
  43: namespace ClassLibraryDemoB
  44: {
  45:     public class ClassB1
  46:     {
  47:         public void Test(int iValue)
  48:         {
  49:             ClassLibraryDemoA.ClassA2 classTwo = new ClassLibraryDemoA.ClassA2();
  50:             classTwo.Test(iValue);
  51:             System.Console.WriteLine(iValue);
  52:         }
  53:     }
  54:  
  55:     public class ClassB2
  56:     {
  57:         public void Test(int iValue)
  58:         {
  59:             ClassLibraryDemoA.ClassA1 classOne = new ClassLibraryDemoA.ClassA1();
  60:             classOne.Test(iValue);
  61:             ClassLibraryDemoA.ClassA3 classThree = new ClassLibraryDemoA.ClassA3();
  62:             classThree.Test(iValue);
  63:             System.Console.WriteLine(iValue);
  64:         }
  65:     }
  66:  
  67:     public class ClassB3
  68:     {
  69:         public void Test(int iValue)
  70:         {
  71:             ClassLibraryDemoA.ClassA3 classThree = new ClassLibraryDemoA.ClassA3();
  72:             classThree.Test(iValue);
  73:             System.Console.WriteLine(iValue);
  74:         }
  75:     }
  76: }
  77:  
  78: namespace ClassLibraryDemoC
  79: {
  80:     public class ClassC1
  81:     {
  82:         public void Test(int iValue)
  83:         {
  84:             System.Console.WriteLine(iValue);
  85:         }
  86:     }
  87: }
  88:  
  89: namespace ClassLibraryDemoD
  90: {
  91:     public class ClassD1
  92:     {
  93:         public void Test(int iValue)
  94:         {
  95:             System.Console.WriteLine(iValue);
  96:         }
  97:     }
  98: }

We then generate a Dependency Graph by Namespace, enabling all three currently available analyzers as shown below.

So what happens?

  1. Namespaces and associated classes that are acting as a hub … get called and call … are shown in blue.
  2. Namespaces and associated classes that not called by anyone … are unreferenced … are shown in violet.
  3. Namespaces and associated classes that calls others, which in turn call the classes again and thereby creating a circular reference, are highlighed in red.

When we create a sequence diagram off the ClassA2.Test() method, to get a clearer view, we suddenly realize that the circular reference is a bad one, which will result in the system eating itself up … like a recursive call that recursively calls itself. At some point the system will throw a no memory exception and implode.

Changing the code as follows, maintains a circular reference between classes, nut not a recursive call that would sooner than later result in a system blow-up. … still showing a circular reference, but not one that will implode ourselves.

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5:  
   6: namespace ClassLibraryDemoA
   7: {
   8:     public class ClassA1
   9:     {
  10:         public void Test(int iValue)
  11:         {
  12:             ClassA2 classTwo = new ClassA2();
  13:             classTwo.TestIn(iValue);
  14:             System.Console.WriteLine(iValue);
  15:         }
  16:     }
  17:     
  18:     public class ClassA2
  19:     {
  20:         public void TestOut(int iValue)
  21:         {
  22:             ClassA1 classOne = new ClassA1();
  23:             classOne.Test(iValue); 
  24:             ClassA3 classThree = new ClassA3();
  25:             classThree.Test(iValue);
  26:             ClassLibraryDemoD.ClassD1 classFour = new ClassLibraryDemoD.ClassD1();
  27:             classFour.Test(iValue); 
  28:             System.Console.WriteLine(iValue);
  29:         }
  30:  
  31:         public void TestIn(int iValue)
  32:         {
  33:             classFour.Test(iValue);
  34:             System.Console.WriteLine(iValue);
  35:         }
  36:     }
  37:  
  38:     public class ClassA3
  39:     {
  40:         public void Test(int iValue)
  41:         {
  42:             ClassLibraryDemoB.ClassB3 classThree = new ClassLibraryDemoB.ClassB3();
  43:             classThree.Test(iValue);
  44:             System.Console.WriteLine(iValue);
  45:         }
  46:     }
  47: }
  48:  
  49: namespace ClassLibraryDemoB
  50: {
  51:     public class ClassB1
  52:     {
  53:         public void Test(int iValue)
  54:         {
  55:             ClassLibraryDemoA.ClassA2 classTwo = new ClassLibraryDemoA.ClassA2();
  56:             classTwo.Test(iValue);
  57:             System.Console.WriteLine(iValue);
  58:         }
  59:     }
  60:  
  61:     public class ClassB2
  62:     {
  63:         public void TestOut(int iValue)
  64:         {
  65:             ClassLibraryDemoA.ClassA1 classOne = new ClassLibraryDemoA.ClassA1();
  66:             classOne.TestIn(iValue);
  67:             ClassLibraryDemoA.ClassA3 classThree = new ClassLibraryDemoA.ClassA3();
  68:             classThree.Test(iValue);
  69:             System.Console.WriteLine(iValue);
  70:         }
  71:         public void TestIn(int iValue)
  72:         {
  73:             System.Console.WriteLine(iValue);
  74:         }
  75:     }
  76:  
  77:     public class ClassB3
  78:     {
  79:         public void Test(int iValue)
  80:         {
  81:             ClassLibraryDemoA.ClassA3 classThree = new ClassLibraryDemoA.ClassA3();
  82:             classThree.Test(iValue);
  83:             System.Console.WriteLine(iValue);
  84:         }
  85:     }
  86: }
  87:  
  88: namespace ClassLibraryDemoC
  89: {
  90:     public class ClassC1
  91:     {
  92:         public void Test(int iValue)
  93:         {
  94:             System.Console.WriteLine(iValue);
  95:         }
  96:     }
  97: }
  98:  
  99: namespace ClassLibraryDemoD
 100: {
 101:     public class ClassD1
 102:     {
 103:         public void Test(int iValue)
 104:         {
 105:             System.Console.WriteLine(iValue);
 106:         }
 107:     }
 108: }

… changes the view as follows:

 

 

 

Cool stuff …