Extend Inaccessible Class In C#

In today's section, we'll see how to extend even inaccessible class and write test against that, but before that let us assume that you have the following class:

  1. internal class internalClass:baseClass    
  2. {    
  3.   public string getFirstValue()    
  4.   {    
  5.       return "extension";    
  6.   }    
  7.   internal class secondClass    
  8.   {    
  9.       internal string getSecondValue()    
  10.       {    
  11.           return "smith";    
  12.       }    
  13.       private class thirdClass    
  14.       {    
  15.           private string getThirdValue()    
  16.           {    
  17.               return "dave";    
  18.           }     
  19.       }    
  20.   }    
  21. }   
Here, It's quite easy to write test for getFirstValue() as in the following code snippet.
  1. [TestMethod]    
  2. public void Class1Test()    
  3. {    
  4.    var obj1 = new internalClass();    
  5.    Assert.AreEqual("extension",obj1.getFirstValue());    
  6. }  
And this will pass. Similarly, we can write test for other (next one) as well and that will also pass.
  1. [TestMethod]    
  2. public void Class2Test()    
  3. {    
  4.     var obj2 = new internalClass.secondClass();    
  5.     Assert.AreEqual("smith", obj2.getSecondValue());    
  6. }    
But, for the third one, which is private, we need to make use reflection as in the following code snippet:
  1. [TestMethod]    
  2. public void Class3Test()    
  3. {    
  4.     var type = typeof (internalClass.secondClass).GetNestedType("thirdClass", BindingFlags.NonPublic);    
  5.     var methodInfo = type.GetMethod("getThirdValue", BindingFlags.NonPublic | BindingFlags.Instance);    
  6.     var obj3 = Activator.CreateInstance(type);    
  7.     Assert.AreEqual("dave",methodInfo.Invoke(obj3,null));    
  8. }   
Here, using reflection, I got the access of that private method and then created instance and hence tested the same. However, let us suppose, you would like to extend this class and make more reusable. In real time project scenario, your extension could be more meaningful. But, here for demo purpose, I am just extending the class to modify the output.
  1. internal  static class internalClassExtensions    
  2. {    
  3.    public static string getFirstValueUpper(this internalClass objClass)    
  4.    {    
  5.        return objClass.getFirstValue().ToUpper();    
  6.    }    
  7. }   
In order to test the same, I can go ahead and write the test case as in the following code snippet:
  1. [TestMethod]    
  2. public void Class1ExtensionTest()    
  3. {    
  4.     var obj1 = new internalClass();    
  5.     Assert.AreEqual("EXTENSION", obj1.getFirstValueUpper());    
  6. }    
Very powerful and easy to use, right?

Similarly, we can go ahead and extend the second class as in the following code snippet:
  1. public static string getSecondValueUpper(this internalClass.secondClass objSecondClass)    
  2. {    
  3.     return objSecondClass.getSecondValue().ToUpper();    
  4. }  
And, again test for the same will look like the following:
  1. [TestMethod]    
  2. public void Class2ExtensionTest()    
  3. {    
  4.     var obj2 = new internalClass.secondClass();    
  5.     Assert.AreEqual("SMITH", obj2.getSecondValueUpper());    
  6. }   
However, if we try to access the third class as in the following, it won't be accessible, since it's private.
  1. //Cannot access private class as shown below    
  2.   /*public static string getThirdValueUpper(this internalClass.secondClass.thirdClass )  
  3.   {  
  4.         
  5.   }*/   
Here, to rescue us again, reflection will come into picture. The following is the code snippet:
  1. //hence, if we really need to extend inaccessible class, we can extend object    
  2.  public static string getThirdValueUpper(this object obj)    
  3.  {    
  4.      var upper = string.Empty;    
  5.      var type = typeof (internalClass.secondClass).GetNestedType("thirdClass", BindingFlags.NonPublic);    
  6.      if (obj.GetType() == type)    
  7.      {    
  8.          //Now, I gain the access of private method as welll    
  9.          var method = type.GetMethod("getThirdValue", BindingFlags.NonPublic | BindingFlags.Instance);    
  10.          var result = method.Invoke(obj, nullas string;    
  11.          upper = result.ToUpper();    
  12.      }    
  13.      return upper;    
  14.  }  
Similarly, we can write test for the same as in the following code snippet:
  1. [TestMethod]    
  2. public void Class3ExtensionTest()    
  3. {    
  4.     var type = typeof(internalClass.secondClass).GetNestedType("thirdClass", BindingFlags.NonPublic);    
  5.     var methodInfo = type.GetMethod("getThirdValue", BindingFlags.NonPublic | BindingFlags.Instance);    
  6.     var obj3 = Activator.CreateInstance(type);    
  7.     Assert.AreEqual("DAVE", obj3.getThirdValueUpper());    
  8. }   
Now let us go ahead and add one abstract class on the top of this and extend the same. The following is the complete code snippet:
  1. using System;    
  2. using System.Collections.Generic;    
  3. using System.Linq;    
  4. using System.Text;    
  5. using System.Threading.Tasks;    
  6.     
  7. namespace ExtensionMethods.Classes    
  8. {    
  9.     internal abstract class baseClass    
  10.     {    
  11.         public virtual string getFirstName()    
  12.         {    
  13.             return "rahul";    
  14.         }    
  15.     
  16.         protected virtual string getSecondName()    
  17.         {    
  18.             return "sahay";    
  19.         }    
  20.     }    
  21.   internal class internalClass:baseClass    
  22.     {    
  23.       public string getFirstValue()    
  24.       {    
  25.           return "extension";    
  26.       }    
  27.       internal class secondClass:baseClass    
  28.       {    
  29.           public override string getFirstName()    
  30.           {    
  31.               return "John";    
  32.           }    
  33.     
  34.           internal string getSecondValue()    
  35.           {    
  36.               return "smith";    
  37.           }    
  38.           private class thirdClass    
  39.           {    
  40.               private string getThirdValue()    
  41.               {    
  42.                   return "dave";    
  43.               }     
  44.           }    
  45.       }    
  46.     }    
  47. }  
And, its extension will look like the following:
  1. using System;    
  2. using System.Collections.Generic;    
  3. using System.Linq;    
  4. using System.Reflection;    
  5. using System.Text;    
  6. using System.Threading.Tasks;    
  7.     
  8. namespace ExtensionMethods.Classes    
  9. {    
  10.    internal  static class internalClassExtensions    
  11.     {    
  12.        public static string getBaseStringUpper(this baseClass objClass)    
  13.        {    
  14.            return objClass.getFirstName().ToUpper();    
  15.        }    
  16.        public static string getFirstValueUpper(this internalClass objClass)    
  17.        {    
  18.            return objClass.getFirstValue().ToUpper();    
  19.        }    
  20.     
  21.        public static string getSecondValueUpper(this internalClass.secondClass objSecondClass)    
  22.        {    
  23.            return objSecondClass.getSecondValue().ToUpper();    
  24.        }    
  25.     
  26.        //Cannot access private class as shown below    
  27.        /*public static string getThirdValueUpper(this internalClass.secondClass.thirdClass )  
  28.        {  
  29.              
  30.        }*/    
  31.     
  32.        //hence, if we really need to extend inaccessible class, we can extend object    
  33.        public static string getThirdValueUpper(this object obj)    
  34.        {    
  35.            var upper = string.Empty;    
  36.            var type = typeof (internalClass.secondClass).GetNestedType("thirdClass", BindingFlags.NonPublic);    
  37.            if (obj.GetType() == type)    
  38.            {    
  39.                //Now, I gain the access of private method as welll    
  40.                var method = type.GetMethod("getThirdValue", BindingFlags.NonPublic | BindingFlags.Instance);    
  41.                var result = method.Invoke(obj, nullas string;    
  42.                upper = result.ToUpper();    
  43.            }    
  44.            return upper;    
  45.        }    
  46.     }    
  47. }   
And, its finished tests will be the following:
  1. using System;    
  2. using System.Reflection;    
  3. using ExtensionMethods.Classes;    
  4. using Microsoft.VisualStudio.TestTools.UnitTesting;    
  5.     
  6. namespace Legacy.Tests.Extension_Tests    
  7. {    
  8.     [TestClass]    
  9.     public class InternalClassTests    
  10.     {    
  11.         [TestMethod]    
  12.         public void Class1Test()    
  13.         {    
  14.             var obj1 = new internalClass();    
  15.             Assert.AreEqual("extension",obj1.getFirstValue());    
  16.         }    
  17.         [TestMethod]    
  18.         public void Class2Test()    
  19.         {    
  20.             var obj2 = new internalClass.secondClass();    
  21.             Assert.AreEqual("smith", obj2.getSecondValue());    
  22.         }    
  23.         [TestMethod]    
  24.         public void Class3Test()    
  25.         {    
  26.             var type = typeof (internalClass.secondClass).GetNestedType("thirdClass", BindingFlags.NonPublic);    
  27.             var methodInfo = type.GetMethod("getThirdValue", BindingFlags.NonPublic | BindingFlags.Instance);    
  28.             var obj3 = Activator.CreateInstance(type);    
  29.             Assert.AreEqual("dave",methodInfo.Invoke(obj3,null));    
  30.         }    
  31.         [TestMethod]    
  32.         public void Class1ExtensionTest()    
  33.         {    
  34.             var obj1 = new internalClass();    
  35.             Assert.AreEqual("EXTENSION", obj1.getFirstValueUpper());    
  36.         }    
  37.         [TestMethod]    
  38.         public void Class2ExtensionTest()    
  39.         {    
  40.             var obj2 = new internalClass.secondClass();    
  41.             Assert.AreEqual("SMITH", obj2.getSecondValueUpper());    
  42.         }    
  43.         [TestMethod]    
  44.         public void Class3ExtensionTest()    
  45.         {    
  46.             var type = typeof(internalClass.secondClass).GetNestedType("thirdClass", BindingFlags.NonPublic);    
  47.             var methodInfo = type.GetMethod("getThirdValue", BindingFlags.NonPublic | BindingFlags.Instance);    
  48.             var obj3 = Activator.CreateInstance(type);    
  49.             Assert.AreEqual("DAVE", obj3.getThirdValueUpper());    
  50.         }    
  51.         [TestMethod]    
  52.         public void baseClassTest()    
  53.         {    
  54.             var obj0 = new internalClass();    
  55.             Assert.AreEqual("rahul",obj0.getFirstName());    
  56.             Assert.AreEqual("RAHUL", obj0.getBaseStringUpper());    
  57.         }    
  58.         [TestMethod]    
  59.         public void Class2OverrideTest()    
  60.         {    
  61.             var obj0 = new internalClass.secondClass();    
  62.             //Below assertion will fail, as this is overriden    
  63.             /*Assert.AreEqual("rahul", obj0.getFirstName());  
  64.             Assert.AreEqual("RAHUL", obj0.getBaseStringUpper());*/    
  65.             Assert.AreEqual("John", obj0.getFirstName());    
  66.             Assert.AreEqual("JOHN", obj0.getBaseStringUpper());    
  67.         }    
  68.     }    
  69. }  
Makes sense, right? Therefore, when you run all the tests, it will flag tests as green as in the following screenshot:

process

There are many other tests other than these, that's why I have not highlighted the same. Thanks for joining me.
Thanks!

 


Similar Articles