Reflection (part 4, professional)
Posted by Bastian M.K. Ohta
Now we start reaching for code that most coders will never touch. Let’s read and use assembly members, which were declared private. This is definitely the twilight zone. In fact there are practical situations where it does make sense to enter that zone, eg. for displaying/changing data in runtime and giving feedback to advanced users. IT support people could detect data issues on a very low-level. The program is probably working fine, it can be input data that screws up calculations.
I guess you already got the idea that we are now entering an area where usually debugger programs have their homeland.
Indirectly I came across reflection of private members yesterday already. I am just putting some more emphasis on it now. The next example code shows how to read fields. It then changes a field value and prints the fields again.
public class WellEncapsulated { private int _HiddenInstanceId = 95; private static int _HiddenStaticId = 1; public int PublicId = 99; private string _HiddenInstanceName = "Rumpelstiltskin"; } // class public static class TotalReflection { private static void PrintFields(object xObject, FieldInfo[] xFields) { Console.WriteLine(); foreach (FieldInfo lField in xFields) { //if (lField.FieldType != typeof(int)) continue; Console.WriteLine("private " + (lField.IsStatic ? "static " : string.Empty) + lField.FieldType.Name.ToString() + " " + lField.Name + " == " + lField.GetValue(xObject)); } } // public static void Test() { object o = new WellEncapsulated(); // we use object to demonstrate the flexibility Type lType = o.GetType(); //MethodInfo[] lMethods = o.GetType().GetMethods(BindingFlags.Instance | BindingFlags.NonPublic); //PropertyInfo[] lProperties = o.GetType().GetProperties(BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo[] lFields = lType.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); if (lFields.Length < 0) return; Console.WriteLine((lType.IsClass ? "class " : "??? ") + lType.Name); PrintFields(o, lFields); // if you can read it, then you can also write to it Console.WriteLine(Environment.NewLine + "changing field value _HiddenInstanceId from 95 to 200"); FieldInfo lFieldToChange = lType.GetField("_HiddenInstanceId", BindingFlags.Instance | BindingFlags.NonPublic); lFieldToChange.SetValue(o, 200); PrintFields(o, lFields); Console.ReadLine(); } // } // class
example output:
class WellEncapsulatedprivate Int32 _HiddenInstanceId == 95
private String _HiddenInstanceName == Rumpelstiltskin
private static Int32 _HiddenStaticId == 1changing field value _HiddenInstanceId from 95 to 200
private Int32 _HiddenInstanceId == 200
private String _HiddenInstanceName == Rumpelstiltskin
private static Int32 _HiddenStaticId == 1
Above we analysed a known object. To get access to unknown objects you have to load or find the assembly. That was covered yesterday in Reflection part 3.
The Mscorlib.dll is the main library in the .Net Framework. Even pieces of Microsoft’s .Net core can be accessed freely by using reflection.
Assembly lAssembly = Assembly.Load("Mscorlib.dll"); Type[] lTypes = lAssembly.GetTypes(); Console.WriteLine(lTypes.Count()); lTypes.Take(100).AsParallel().ForAll(x => Console.WriteLine(x.FullName));
You can find members by their names as well. Wildcards are no problem. “Get*” would find all names starting with “Get” like “GetTypes()”.
public static void Test3() { Type lType = Type.GetType("System.String"); BindingFlags lFlags = BindingFlags.Static | BindingFlags.Public; Console.WriteLine("All Members starting with E"); Console.WriteLine("================================="); MemberInfo[] lMemberInfos1 = lType.FindMembers(MemberTypes.All, lFlags, Type.FilterName, "E*"); foreach (MemberInfo m in lMemberInfos1) Console.WriteLine("{0}: {1}", m.MemberType, m); Console.WriteLine(); Console.WriteLine("All Members starting with Compare"); Console.WriteLine("================================="); MemberInfo[] lMemberInfos2 = lType.FindMembers(MemberTypes.All, lFlags, Type.FilterName, "Compare*"); foreach (MemberInfo m in lMemberInfos2) Console.WriteLine("{0}: {1}", m.MemberType, m); Console.ReadLine(); } //
example output:
All Members starting with E
=================================
Method: Boolean Equals(System.String, System.String)
Method: Boolean Equals(System.String, System.String, System.StringComparison)
Field: System.String EmptyAll Members starting with Compare
=================================
Method: Int32 Compare(System.String, System.String)
Method: Int32 Compare(System.String, System.String, Boolean)
Method: Int32 Compare(System.String, System.String, System.StringComparison)
Method: Int32 Compare(System.String, System.String, System.Globalization.CultureInfo, System.Globalization.CompareOptions)
Method: Int32 Compare(System.String, System.String, Boolean, System.Globalization.CultureInfo)
Method: Int32 Compare(System.String, Int32, System.String, Int32, Int32)
Method: Int32 Compare(System.String, Int32, System.String, Int32, Int32, Boolean)
Method: Int32 Compare(System.String, Int32, System.String, Int32, Int32, Boolean, System.Globalization.CultureInfo)
Method: Int32 Compare(System.String, Int32, System.String, Int32, Int32, System.Globalization.CultureInfo, System.Globalization.CompareOptions)
Method: Int32 Compare(System.String, Int32, System.String, Int32, Int32, System.StringComparison)
Method: Int32 CompareOrdinal(System.String, System.String)
Method: Int32 CompareOrdinal(System.String, Int32, System.String, Int32, Int32)
I am not going further today, because we are entering CodeDOM now. I will show you how to generate objects at runtime in the next days. Stay tuned!
Posted on January 14, 2014, in C#, Professional, Reflection and tagged advanced, C#, C-sharp, metadata, professional, programming, reference type, reflection, Source code. Bookmark the permalink. Leave a comment.
Leave a comment
Comments 0