Reflection is a technique provided by. NET to access the contents of a class or class, which allows you to access a class at compile time with virtually no knowledge of a class, supports discovery, access, invocation of a class using a string, and uses examples to introduce four ways to use reflection
First, a class is used to simulate the called class.
public class TestClass { private string testtype; public string Testtype { get {return testtype;} set {Testtype = value;} } private string testType2; public string TestType2 { get {return testType2;} set {testType2 = value;} } Public TestClass () { testType2 = "Test"; } public int test1 () { int i = 1; i++; return i; } public void testsomething () { int i = 0; } }
The above code is for testing only, generally estimated that no one will write such code, do not despise, in order to simulate the reflection of the call, I enclose this class in a class library called Testlibrary.dll.
Then first the code of the four methods is listed first, then the explanation
delegate void DelegateTest (Type t); Private Const BindingFlags flags = BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | bindingflags.static | BindingFlags.Instance;
//Method 1 private void TestInvoke1 (Type t) {Object obj = T.invokemem ber (NULL, Flags | Bindingflags.createinstance, NULL, NULL, NULL); Console.WriteLine (obj. GetType (). ToString ()); String testresult= t.invokemember ("testType2", Flags | Bindingflags.getfield, NULL, obj, NULL). ToString (); Console.WriteLine (TestResult); T.invokemember ("TestType2", Flags | Bindingflags.setfield, NULL, obj,new object[]{"Grass Mud Horse"}); testresult= t.invokemember ("testType2", Flags | Bindingflags.getfield, NULL, obj, NULL). ToString (); Console.WriteLine (TestResult); TestResult = T.invokemember ("Test1", BindingFlags.InvokeMethod, NULL, obj, NULL). ToString (); Console.WriteLine (TestResult); }
//Method 2 private void TestInvoke2 (Type t) {ConstructorInfo ctor = t . GetConstructor (new type[] {}); Object obj = ctor. Invoke (new object[] {}); FieldInfo fi = T.getfield ("Testtype", flags); Fi. SetValue (obj, "Nina"); Console.WriteLine (FI. GetValue (obj)); MethodInfo mi = t.getmethod ("test1", flags); string result = mi. Invoke (obj, null). ToString (); Console.WriteLine (result); }
//Method 3 delegate int testdelegate (); private void TestInvoke3 (Type t) {Object obj = activator.createinstance (t); MethodInfo mi = t.getmethod ("test1", flags); var test1 = (testdelegate) (MI. CreateDelegate (typeof (Testdelegate), obj)); int i = test1 (); Console.WriteLine (i.ToString ()); PropertyInfo pi = t.getproperty ("Testtype", flags); var settesttype = (action<string>) delegate.createdelegate (typeof (Action<string>), obj, pi. GetSetMethod ()); try {settesttype ("the"); } catch {Console.WriteLine ("Cannot write! "); } var gettesttype = (func<string>) delegate.createdelegate (typeof (Func<string>), obj, pi. Getgetmethod ()); Console.WriteLine ("Get Results:" + gettesttype ()); }
Method 4 private void TestInvoke4 (Type t) { Dynamic obj = activator.createinstance (t); Try { Obj.testtype = "peat"; Console.WriteLine (Obj.testType.ToString ()); } Catch { Console.WriteLine ("Private field cannot read or write"); } Try { obj. Testtype = "Peat 2"; Console.WriteLine (obj. Testtype); } Catch { Console.WriteLine ("Private property cannot be read or written"); } Try { func<int> test = () =>obj.test1 (); Console.WriteLine (Test ()); } Catch { Console.WriteLine ("Private method cannot read or write"); } }
First look at the parameters passed in these four methods, there is a type of parameter, this parameter is to take advantage of the type of class to be accessed by reflection, this first, let's first describe how to obtain this type of class access.
First of all, Method 1, the most direct way, but the reflection is a comparison of the consumption of performance of the call, Method 1 per call method or property will be one time binding, the performance of the consumption is relatively large, slower, first using the type of the The InvokeMember method calls a constructor of type T to construct an instance, but because we do not know what type it is during the run, it can only be assigned to an object. The first parameter of InvokeMember represents the name of the content to be accessed, such as a property or the name of a method, as is the access constructor method, we pass in null value NULL. The second parameter is the flag that controls the execution of the binding, specifying which types to bind to, separated by a | symbol, such as flag in the example, the specified declaredonly specifies that the reflection does not take into account the inheritance type, nonpublic specifies reflection nonpublic members, and so on, So reflection is accessible to private members without special handling of the data, the fourth argument is the bound instance, the null value is passed when the constructor method is called, the Call property or the field or method needs to pass in the object instance returned by the construction method, and the last parameter is the parameter to pass in object[] Type is passed in. With this understanding, it is possible to invoke the various types of an unknown class using the InvokeMember method, which gives an example of the calling field and the method, and note that the access testType2 is a private field, but it is still available for access.
Then, Method 2, Method 2 provides a way to bind a property, multiple calls, when multiple instances need to call the same method repeatedly, this method can provide better performance, because all operations are bound only once, this time, using another way to call the constructor method, call type The GetConstructor method of the type, which searches for a matching constructor in the assembly based on the parameter type specified by the passed parameter, and returns a ConstructorInfo instance that provides access to the constructor, Above Method 2 We pass in an empty type[] array, then the instance returned by this method will provide access to the parameterless construction method, then call the instance's Invoke method and pass in the parameter to get an instance of the type, as well as an object. We then gain access to specific fields and methods through the type GetField and GetMethod methods, and then access the corresponding methods and fields, and, in the same way, gain access to the property through the GetProperty method.
Method 3 provides a way to take advantage of the delegate access type, which is suitable for repeated calls to the same member within the same instance, and the performance of this method is better than the method provided by method 2 when the same member within the same object is called multiple times. Still constructs an instance and then gets access to the member, but this time constructs a delegate and points this delegate to the member, but this method does not provide access to the field, and access to the property is achieved by constructing a delegate to the property's get accessor or set accessor, for the purpose of accessing the property.
Method 4 provides a way to access the class using dynamic, and after we have constructed the instance we return an object, but this time we assign the return value to a dynamic, which will be parsed at run time and not parsed at compile time. Call in this way is mainly easy to understand, intuitive, and it also provides a good performance, but there is a drawback, because it is not compiled at the time to parse, so you can not take advantage of the powerful smart hint function, compile time will not error, really achieve pure hand, you may be the main inside with a lot of try Catch, mainly because it is possible to access non-existent members or private members in this way, this time the error will be captured, this is also necessary.
Okay, here's a quick explanation of these four ways, and then let's talk about discovering class members and getting to the class type.
Assembly a = Assembly.LoadFrom ("Testlibrary.dll"); foreach (Type t in A.getexportedtypes ()) { if (t.name.tostring () = = "TestClass") { Console.WriteLine ( T.fullname); Object o = activator.createinstance (t); Console.WriteLine (O.gettype ()); foreach (MemberInfo info in t.getmembers (bindingflags.declaredonly | BindingFlags.NonPublic | BindingFlags.Public | bindingflags.static | bindingflags.instance)) { Console.WriteLine (info); } TestInvoke1 (t); } }
The code above provides a way to discover the members of a class using the Assembly.LoadFrom method to load our previously generated assembly, and the Getexportedtypes method gets all the public types that can be obtained by the type to get the type of the member inside the class, and all we need at this time is the type of the class, which is then passed into the appropriate method. The specific process can refer to the sample code, are relatively simple, not more verbose.
Four ways to use reflection