Search This Blog

Loading...

Monday, January 28, 2008

Code Snippets to Access Internal Classes and Members

Using reflection to access internal classes or members is generally considered as a bad coding practice in .Net or Java. The classes and members are usually hidden for a good reason: you want your methods and members to be encapsulated from unnecessary exposure so that the API callers do not have to process too many irrelevant information. If you find that you need to access internal classes or modify private members than it maybe possible that either:
  1. The API is not well-designed in that not enough information are exposed for external consumption
  2. The callers are demanding too much information

Either cases reflect poor class design and should be fixed. There should be no need to resort to reflection in order to access or modify internal values.

But there are some conditions when you have to use reflection to access non-public modules. If you need to call a third party component that you don't have the source code and you are in desperate need to use the internal members, then you have no choice but to resort to reflection. I will consider this case as a hack and will not encourage it.

But using reflection to test internal methods is good from my point of view. I will allow, or even encourage one to unit test the internal methods or classes via reflection. Some won't use the techniques in unit test code if those techniques are not used in production code. Some even argued that private members and methods are code smells. But I am less dogmatic than that. I do recognize that there are times when private methods are in need of testing, say for example when the private methods are in themselves complicated. So I compile a list of utility methods that enable one to access protected, internal and private classes and methods via reflection. All the below code snippet can compile on Visual Studio 2003 and above.

Disclaimer: Use these code snippets as your own risk!

Get Non-Public Members
     public static object GetMembers(object objName, string propertyName)
{
Type objType = objName.GetType();
FieldInfo fild =GetFieldInfo(objType, propertyName);
if (fild == null)
{
throw new ArgumentException("There is no field '" +
propertyName + "' for type '" + objName.GetType().ToString() + "'.");
}
return fild.GetValue(objName);

}


Set Non-Public Members
     public static void SetMembers(object objName, string propertyName, object aValue )
{
FieldInfo fld = GetFieldInfo(objName.GetType(), propertyName);
if (fld == null)
{
throw new ArgumentException("There is no field '" +
propertyName + "' for type '" + objName.GetType().ToString() + "'.");
}
fld.SetValue(objName, aValue);
}


Get Field Info Method
     private static FieldInfo GetFieldInfo(Type objType, string propertyName )
{

FieldInfo fild = objType.GetField(propertyName,BindingFlags.Instance | BindingFlags.NonPublic);
if(fild!=null)
return fild;
if(objType.GetType()==typeof(object))
return null;
return GetFieldInfo(objType.BaseType, propertyName);
}


Run Non-Public Method
     public static object RunInstanceMethod(object objInstance, string strMethod, object [] aobjParams)
{
BindingFlags eFlags = BindingFlags.Instance | BindingFlags.Public |
BindingFlags.NonPublic;
return RunMethod(strMethod, objInstance, aobjParams, eFlags);
}

private static object RunMethod(string strMethod, object objInstance, object [] aobjParams, BindingFlags eFlags)
{
Type t = objInstance.GetType();
MethodInfo m = GetMethod(t, strMethod, eFlags);
if (m == null)
{
throw new ArgumentException("There is no method '" +
strMethod + "' for type '" + t.ToString() + "'.");
}

object objRet = m.Invoke(objInstance, aobjParams);
return objRet;


}

private static MethodInfo GetMethod(Type t, string strMethod, BindingFlags eFlags )
{
MethodInfo m = t.GetMethod(strMethod, eFlags);
if(m!=null)
return m;
if(t.GetType()==typeof(object))
return null;
return GetMethod(t.BaseType, strMethod, eFlags);

}


No comments: