Wednesday, November 16, 2011

How to access a private member outside a class


There is a misconception between C# developers that member access specifier like Private restricts the accessibility outside of that class where it is declared.
Today I am going to show you that it is possible via reflection to not only access those private members but you can change and manipulate them as you want.
Here is the link from Microsoft that tells us something about member access specifiers.
Worth noting the definition of Private access specifier

private
The type or member can be accessed only by code in the same class or struct

Alright, Lets jump on to the code to demonstrate how to access private member.
Lets create a Console Application and name it as ReflecitonDemo. Put the solution name AccessingPrivate.
Right click on ReflectionDemo project to add a class. Let's name it as SampleClass.
Type or paste the following snippet into SampleClass

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ReflectionDemo
{
     class SampleClass
    {
        private string privateVariable = "Hey! I am private string variable of SampleClass";
        private String PrivateProperty
        {
            get
            {
                return privateVariable;
            }
            set
            {
                privateVariable = value;
            }
        }
        private string PrivateMethod()
        {
            return "Hey! I am private Method of SampleClass.";
        }
     
    }
}



As you can see this class has 3 private members. A variable, property that uses that string variable and a private method that returns a string.
Double click on your Program.cs file and write/paste the following code in it.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

using Payroll;

namespace ReflectionDemo
{
    class Program
    {
        static string decorator="**************************************************************";
        static void ShowMemembers(object type)
        {
            Console.WriteLine("Showing all the members of " +type.GetType().Name+" class");
            foreach (MemberInfo m in type.GetType().GetMembers(BindingFlags.Instance | BindingFlags.NonPublic|BindingFlags.DeclaredOnly))
            {
                Console.WriteLine(m.Name);
            }
            Console.WriteLine(decorator);
            Console.ReadLine();
        }
        static void InvokePrivateMethod(object type,string methodName)
        {
            //Let's inovke the private method of this class
             Console.WriteLine(decorator);
            
            Console.WriteLine( type.GetType().GetMethod(methodName,BindingFlags.Instance|BindingFlags.NonPublic|BindingFlags.InvokeMethod|BindingFlags.DeclaredOnly).Invoke(type, null));
            Console.WriteLine(decorator);
            Console.ReadLine();
        }
        private static void ChangePrivateField(Object type, string fieldName,object newValue)
        {
            FieldInfo field = type.GetType().GetField(fieldName,BindingFlags.Instance|BindingFlags.NonPublic|BindingFlags.DeclaredOnly);
            Console.WriteLine("Old value of private field: '{0}' of Class {1} is :\r\n  ",fieldName,type.GetType().Name);
            Console.WriteLine(decorator);
            Console.WriteLine(field.GetValue(type));
            Console.WriteLine(decorator);
            
                    
            field.SetValue(type, newValue);
            //Lets see what we did with poor private variable.
            Console.WriteLine("New value of private field: '{0}' of Class {1} is :\r\n  ", fieldName, type.GetType().Name);
            Console.WriteLine(decorator);
            Console.WriteLine(type.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.DeclaredOnly).GetValue(type));
            Console.WriteLine(decorator);
         
            Console.ReadLine();
       
        }
        static void Main(string[] args)
        {
            //http://msdn.microsoft.com/en-us/library/ms173121.aspx

            SampleClass sc = new SampleClass();

            ShowMemembers(sc);
            Console.WriteLine("Calling Private method of SampleClass");
            InvokePrivateMethod(sc, "PrivateMethod");
            Console.WriteLine("Calling Private variable of SampleClass");
            ChangePrivateField(sc, "privateVariable","Your wish my command");

            Console.Clear();
            List<string> list = new List<string>();
            list.Add("Talal");
            list.Add("Khan");
            Console.WriteLine(decorator);
            Console.WriteLine("List count is: {0}", list.Count);
            Console.WriteLine(decorator);
            Console.ReadLine();
            Console.Clear();
            ShowMemembers(list);

            ChangePrivateField(list, "_size",10);


            Console.WriteLine(decorator);
            Console.WriteLine("List count is: {0}", list.Count);
            Console.WriteLine(decorator);


            Console.Clear();

            Employee John = new Employee();
            John.EmployeeId = 1001;
            John.FirstName = "John";
            John.LastName = "Teddy";
            John.Address = "122 Awesome drive, Richmond, VA, 23238";
            John.GetEmployeeSalarybyID(John.EmployeeId);
            Console.WriteLine(John.Salary.ToString());


            Employee Mary = new Employee();
            Mary.EmployeeId = 1002;
            John.FirstName = "Mary";
            John.LastName = "Jones";
            John.Address = "1345 Noway drive, Richmond, VA, 23238";
            Mary.GetEmployeeSalarybyID(Mary.EmployeeId);
            Console.WriteLine(Mary.Salary.ToString());

           
            Employee Talal = new Employee();
            Talal.EmployeeId = 1003;
            John.FirstName = "Talal";
            John.LastName = "Khan";
            John.Address = "900 pump road, Richmond, VA, 23238";
            Talal.GetEmployeeSalarybyID(Talal.EmployeeId);
            Console.WriteLine(Talal.Salary.ToString());

            ChangePrivateField(Talal, "_Salary", 99999.99);
            Console.WriteLine(Talal.Salary.ToString());
            Console.ReadLine();
        }
   }
}

The point of interest in this code snippets are three static methods named
  1.  ShowMemembers
  2.  InvokePrivateMethod
  3.  ChangePrivateField
The names are pretty self explanatory.
Let's jump on these method and see what they does.

ShowMembers Function; This method uses reflection to show only private members of a type that is passed as its parameter.In our above code, we are passing SampleClass type to this method as parameter.
The output if you run the project will show you all the private members defined only in this type, no inherited or child's type members will be shown.
Let's dig into this function line by line.


Console.WriteLine("Showing all the members of " +type.GetType().Name+" class");


This line is self explanatory. This line will display a string on console that says "Showing all the members of SampleClass class".



foreach (MemberInfo m in type.GetType().GetMembers(BindingFlags.Instance | BindingFlags.NonPublic|BindingFlags.DeclaredOnly))
            {
                Console.WriteLine(m.Name);
            }


Ah! The following code snippet is what you need to access the private members of a type. As you can see in this code, reflection is being used to get the type of the type that has been passed as a parameter and then once we found that type, we use a built in function called GetMemebers() which is a overloaded method to return an array of string. This method takes BindingFlags enum type as a parameter. Now that our motive is to get all the private member of this type only, we have to use bit-wise shift operator for BindingFlags.
That's why I have used, Instance, NonPublic(for priavate Members) and DeclaredOnly(only from this type) flag. You can see the details of each flag on MSDN site here.


Guess what, this code will spits out the following output on console.




If you look closely in Sample class we have defined only 3 private members. Private variable,  private property and private method. but the output shows 2 more properties; get_PrivateProperty & set_PrivateProperty. Remember, in .Net a property is nothing but combination of merely a getter and setter function.
Alright, now that we have seen all the private members of this class let's jump to next function called InvokePrivateMethod.


InvokePrivateMethod Function:
This method also uses reflection to invoke a private method. Once you have identified the name of the private function as in our case it is "PrivateMethod", We pass this alone with the object to invoke it.
Let's dig into this code base.



Console.WriteLine( type.GetType().GetMethod(methodName,BindingFlags.Instance|BindingFlags.NonPublic|BindingFlags.InvokeMethod|BindingFlags.DeclaredOnly).Invoke(type, null));



As you can see the above line uses a built in overloaded function GetMethod which uses two parameters, name of parameter and binding flag to reach out that function.
In addition to the binding flags that we discussed previous we have used another binding flag called BindingFlags.InvokeMethod which is used to tell the compiler that this method is to be invoked.
Once we get the required method from GetMethod(), we use Invoke function of MethodBase class to invoke this method and pass the object(in this case SampleClass).
The following is the output on the console.





Did you see, we called a private method named PrivateMethod of class SampleClass. Impressive?



ChangePrivateField Function:
As it name indicates this generic method I have created is used to change the value of any private field in any class. You can see the default value of string (privateVariable) in SampleClass is "Hey! I am private string variable of SampleClass". By calling this method, I am able to change that string to "Your wish  is my command".
Let's see how.


FieldInfo field = type.GetType().GetField(fieldName,BindingFlags.Instance|BindingFlags.NonPublic|BindingFlags.DeclaredOnly);




This code is being used to get the private field of the SampleClass and store the reference in FieldInfo type. Now that we have got the private field, we can get its current value.


field.GetValue(type));


Now, I can see what you are thinking. If you can get the value, can we set the value? Sure, why not.
There is method called SetValue that you can use to change its value.



field.SetValue(type, newValue);



As you can see, this method expect two parameter, the object to which this field belong and new value.
Here is the output of this method on the console.






Now that we have learned how to manipulate these private field. Do you want to try this technique to some of the classes shipped with .Net such as List class?

Alright then, lets declare a list of string and add 2 string to that list as show below.


Console.Clear();
List<string> list = new List<string>();
list.Add("Talal");
list.Add("Khan");
Console.WriteLine(decorator);
Console.WriteLine("List count is: {0}", list.Count);
Console.WriteLine(decorator);




The output of this code should be 2. No tricks in there.
Now lets call ShowMembers function and pass this list object to that method.
You will get a list of all the private members as expected. Now that I pick _size variable from those private members list. 
This is private variable of type int which Count read-only property uses to display you the count. I want to mess with it. I want to change the count from 2 to 200. Can I do that? Well before reading this article you probably would say No. But now your answer would be yes.
Call ChangePrivateField with list object, _size as fieldName, and 200 as new value.




 ChangePrivateField(list, "_size",200);


Now output the count again.


Console.WriteLine(decorator);
Console.WriteLine("List count is: {0}", list.Count);
Console.WriteLine(decorator);



What did you see? 200 or 2 :)
Okay fair enough, you can now play with any type that has reflection permission on it or the type's code is not obfuscated. 
Cheers.

Source Code

 

No comments:

Post a Comment