Reflection in .NET
来源:互联网 发布:弱网络测试 编辑:程序博客网 时间:2024/05/17 04:15
Contents
- Introduction
- What is.NET Reflection?
- Road Map
- The System.Reflection Namespace
- The System.Type Class
- Using System.Object.GetType()
- Using System.Type.GetType()
- Using the typeof () C# Operator
- Type Properties
- Type Methods
- Reflecting on Methods
- Reflecting on Fields and Properties
- Reflecting on Implemented Interfaces
- Reflecting on Method Parameters and Return Values
- Reflecting on Constructor
- Assembly Class
- Dynamically Loading an Assembly
- Late Binding
- Reflection Emit
Introduction
In this article, I have tried to cover all the topics from .NET Reflection with examples. I have stated with the definition of.NET Reflection and its road map, a list of mostly used classes theSystem.Reflection
namespace provides, and the importance of theType
class in .NET Reflection. You will also learn how to get the type information using different ways. Use of properties and methods of theType
class in .NET Reflection, with examples, are explained in this article. You will also see advancedReflection topics like dynamically loading an assembly and late binding, at the end of this article.
What is .NETReflection?
.NET Framework's Reflection API allows you to fetch type (assembly) information at runtime programmatically. We can also achieve late binding by using.NET Reflection. At runtime, theReflection mechanism uses the PE file to read information about the assembly.Reflection enables you to use code that is not available at compile time..NET Reflection allows an application to collect information about itself and also to manipulate on itself. It can be used effectively to find all types in an assembly and/or dynamically invoke methods in an assembly. This includes information about the type, properties, methods, and events of an object. WithReflection, we can dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object and invoke its methods or access its fields and properties. We can also access attribute information using Reflection.
Using Reflection, you can get any kind of information which you can see in a class viewer; for example, information on the methods, properties, fields, and events of an object.
The System.Reflection
namespace and theSystem.Type
class plays a very important role in .NET Reflection. These two work together and allow you toreflect over many other aspects of a type.
Road Map
The System.Reflection Namespace
The System.Reflection
namespace contains the classes and interfaces that provide a managed view of loaded types, methods, and fields, with the ability to dynamically create and invoke types; this process is known as Reflection in .NET framework. We will take a look at some of the commonly used classed here:
Assembly
Represents an assembly, which is a reusable, versionable, and self-describing building block of a Common Language Runtime application. This class contains a number of methods that allow you to load, investigate, and manipulate an assembly.Module
Performs Reflection on a module. This class allows you to access a given module within a multi-file assembly.AssemblyName
This class allows you to discover numerous details behind an assembly's identity. An assembly's identity consists of the following:- Simple name
- Version number
- Cryptographic key pair
- Supported culture
EventInfo
This class holds information for a given event. Use the EventInfo
class to inspect events and to bind to event handlers.FieldInfo
This class holds information for a given field. Fields are variables defined in the class.FieldInfo
provides access to the metadata for a field within a class, and provides dynamic set and get functionality for the field. The class is not loaded into memory untilInvoke
or get
is called on the object.MemberInfo
The MemberInfo
class is the abstract base class for classes used to obtain information about all members of a class (constructors, events, fields, methods, and properties).MethodInfo
This class contains information for a given method.ParameterInfo
This class holds information for a given parameter.PropertyInfo
This class holds information for a given property.Before we start using Reflection, it is necessary to understand theSystem.Type
class.
In order to continue with all the examples given in this article, I am using aCar
class as an example. It will look like this:
// ICar.cs - Interface using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Reflection { interface ICar { bool IsMoving(); } }// Car.cs - Class using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Reflection { internal class Car { //public variables public string Color; //private variables //String licensePlate; // e.g. "Californi 111 222" //double maxSpeed; // in kilometers per hour //int startMiles; // Stating odometer reading //int endMiles; // Ending odometer reading //double gallons; // Gallons of gas used between the readings //private vaiables private int _speed; //Speed - read-only property to return the speed public int Speed { get { return _speed; } } //Accelerate - add mph to the speed public void Accelerate(int accelerateBy) { //Adjust the speed _speed += accelerateBy; } //IsMoving - is the car moving? public bool IsMoving() { //Is the car's speed zero? if (Speed == 0) { return false; } else { return true; } } //Constructor public Car() { //Set the default values Color = "White"; _speed = 0; } //Over loaded constructor public Car(string color, int speed) { Color = color; _speed = speed; } //methods public double calculateMPG(int startMiles, int endMiles, double gallons) { return (endMiles - startMiles) / gallons; } }}// SportsCar.cs - Class using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Reflection { internal class SportsCar : Car { //Constructor public SportsCar() { //Change the default values Color = "Green"; } }}
The System.Type Class
The System.Type
class is the main class for the .NET Reflection functionality and is the primary way to access metadata. TheSystem.Type
class is an abstract class and represents a type in the Common Type System (CLS).
It represents type declarations: class types, interface types, array types, value types, enumeration types, type parameters, generic type definitions, and open or closed constructed generic types.
Use the members of Type
to get information about a type declaration, such as the constructors, methods, fields, properties, and events of a class, as well as the module and the assembly in which the class is deployed.
There are tree ways to obtain a Type
reference:
Using System.Object.GetType()
This method returns a Type
object that represents the type of an instance. Obviously, this approach will only work if you have compile-time knowledge of the type.
// ObjectGetTypeDemo.cs using System; namespace Reflection { class ObjectGetTypeDemo { static void Main(string[] args) { Car c = new Car(); Type t = c.GetType(); Console.WriteLine(t.FullName); Console.ReadLine(); } } }
Output
Reflection.Car
Using System.Type.GetType()
Another way of getting type information in a more flexible manner is the GetType()
static method of the Type
class which gets the type with the specified name, performing a case-sensitive search.
Type.GetType()
is an overloaded method that accepts the following parameters:
- fully qualified string name of the type you are interested in examining
- exception that should be thrown if the type cannot be found
- establishes the case sensitivity of the string
// TypeGetTypeDemo.cs using System; namespace Reflection { class TypeGetTypeDemo { static void Main(string[] args) { // Obtain type information using the static Type.GetType() method. // (don't throw an exception if Car cannot be found and ignore case). Type t = Type.GetType("Reflection.Car", false, true); Console.WriteLine(t.FullName); Console.ReadLine(); } } }
Output
Reflection.Car
Using the typeof () C# Operator
The final way to obtain type information is using the C# typeof
operator. This operator takes the name of the type as a parameter.
// TypeofDemo.cs using System; namespace Reflection { class TypeofDemo { static void Main(string[] args) { // Get the Type using typeof. Type t = typeof(Car); Console.WriteLine(t.FullName); Console.ReadLine(); } } }
Output
Reflection.Car
Type Properties
The System.Type
class defines a number of members that can be used to examine a type's metadata, a great number of which return types from theSystem.Reflection
namespace.
You can split the properties implemented by Type
into three categories:
- A number of properties retrieve the strings containing various names associated with the class, as shown in the following table:PropertyReturns
Name
The name of the data type.FullName
The fully qualified name of the data type (including the namespace name).Namespace
The name of the namespace in which the data type is defined. - It is also possible to retrieve references to further type objects that represent related classes, as shown in the following table:PropertyReturns Type Reference Corresponding To
BaseType
Immediate base type of this type.UnderlyingSystemType
The type that this type maps to in the .NET runtime (recall that certain.NET base types actually map to specific predefined types recognized by IL). - A number of Boolean properties indicating whether this type is, for example, a class, an enum, and so on.TypeMeaning in Life
IsAbstract
IsArray
IsClass
IsCOMObject
IsEnum
IsGenericTypeDefinition
IsGenericParameter
IsInterface
IsPrimitive
IsPublic
IsNestedPrivate
IsNestedPublic
IsSealed
IsValueType
IsPointer
Here is the example of displaying type information using the System.Type
class properties:
// TypePropertiesDemo.cs using System; using System.Text; using System.Reflection; namespace Reflection { class TypePropertiesDemo { static void Main() { // modify this line to retrieve details of any other data type // Get name of type Type t = typeof(Car); GetTypeProperties(t); Console.ReadLine(); } public static void GetTypeProperties(Type t) { StringBuilder OutputText = new StringBuilder(); //properties retrieve the strings OutputText.AppendLine("Analysis of type " + t.Name); OutputText.AppendLine("Type Name: " + t.Name); OutputText.AppendLine("Full Name: " + t.FullName); OutputText.AppendLine("Namespace: " + t.Namespace); //properties retrieve references Type tBase = t.BaseType; if (tBase != null) { OutputText.AppendLine("Base Type: " + tBase.Name); } Type tUnderlyingSystem = t.UnderlyingSystemType; if (tUnderlyingSystem != null) { OutputText.AppendLine("UnderlyingSystem Type: " + tUnderlyingSystem.Name); //OutputText.AppendLine("UnderlyingSystem Type Assembly: " + // tUnderlyingSystem.Assembly); } //properties retrieve boolean OutputText.AppendLine("Is Abstract Class: " + t.IsAbstract); OutputText.AppendLine("Is an Arry: " + t.IsArray); OutputText.AppendLine("Is a Class: " + t.IsClass); OutputText.AppendLine("Is a COM Object : " + t.IsCOMObject); OutputText.AppendLine("\nPUBLIC MEMBERS:"); MemberInfo[] Members = t.GetMembers(); foreach (MemberInfo NextMember in Members) { OutputText.AppendLine(NextMember.DeclaringType + " " + NextMember.MemberType + " " + NextMember.Name); } Console.WriteLine(OutputText); } } }
Output
Analysis of type Car Type Name: Car Full Name: Reflection.Car Namespace: Reflection Base Type: Object UnderlyingSystem Type: Car Is Abstract Class: False Is an Arry: False Is a Class: True Is a COM Object : False
Public members
Reflection.Car Method get_Speed Reflection.Car Method Accelerate Reflection.Car Method IsMoving Reflection.Car Method calculateMPG System.Object Method ToString System.Object Method Equals System.Object Method GetHashCode System.Object Method GetType Reflection.Car Constructor .ctor Reflection.Car Constructor .ctor Reflection.Car Property Speed Reflection.Car Field Color
Type Methods
Most of the methods of System.Type
are used to obtain details of the members of the corresponding data type - the constructors, properties, methods, events, and so on. Quite a large number of methods exist, but they all follow the same pattern.
ConstructorInfo
GetConstructor()
, GetConstructors()
These methods allow you to obtain an array representing the items (interface, method, property, etc.) you are interested in. Each method returns a related array (e.g.,GetFields()
returns a FieldInfo
array, GetMethods()
returns aMethodInfo
array, etc.). Be aware that each of these methods has a singular form (e.g.,GetMethod()
, GetProperty()
, etc.) that allows you to retrieve a specific item by name, rather than an array of all related items.EventInfo
GetEvent()
, GetEvents()
FieldInfo
GetField()
, GetFields()
InterfaceInfo
GetInterface()
, GetInterfaces()
MemberInfo
GetMember()
, GetMembers()
MethodInfo
GetMethod()
, GetMethods()
PropertyInfo
GetProperty()
, GetProperties()
FindMembers()
This method returns an array of MemberInfo
types based on a search criteria.Type
GetType()
This static method returns a Type
instance given a string name. InvokeMember()
This method allows late binding to a given item.For example, two methods retrieve details of the methods of the data type: GetMethod
() and GetMethods
().
Type t = typeof(Car); MethodInfo[] methods = t.GetMethods(); foreach (MethodInfo nextMethod in methods) { // etc. }
Reflecting on Methods
GetMethod()
returns a reference to a System.Reflection.MethodInfo
object, which contains details of a method. Searches for the public method with the specified name.
GetMethods()
returns an array of such references. The difference is thatGetMethods()
returns details of all the methods, whereas GetMethod()
returns details of just one method with a specified parameter list.
Both methods have overloads that take an extra parameter, a BindingFlags
enumerated value that indicates which members should be returned - for example, whether to return public members, instance members, static members, and so on.
MethodInfo
is derived from the abstract class MethodBase
, which inheritsMemberInfo
. Thus, the properties and methods defined by all three of these classes are available for your use.
For example, the simplest overload of GetMethods()
takes no parameters:
// GetMethodsDemo.cs using System; using System.Reflection; namespace Reflection { class GetMethodsDemo { static void Main() { // Get name of type Type t = typeof(Car); GetMethod(t); GetMethods(t); Console.ReadLine(); } // Display method names of type. public static void GetMethods(Type t) { Console.WriteLine("***** Methods *****"); MethodInfo[] mi = t.GetMethods(); foreach (MethodInfo m in mi) Console.WriteLine("->{0}", m.Name); Console.WriteLine(""); } // Display method name of type. public static void GetMethod(Type t) { Console.WriteLine("***** Method *****"); //This searches for name is case-sensitive. //The search includes public static and public instance methods. MethodInfo mi = t.GetMethod("IsMoving"); Console.WriteLine("->{0}", mi.Name); Console.WriteLine(""); } } }
Output
***** Method ***** ->IsMoving ***** Methods ***** ->get_Speed ->Accelerate ->IsMoving ->calculateMPG ->ToString ->Equals ->GetHashCode ->GetType
Here, you are simply printing the name of the method using the MethodInfo.Name
property. As you might guess,MethodInfo
has many additional members that allow you to determine if the method isstatic
, virtual
, or abstract
. Also, the MethodInfo
type allows you to obtain the method's return value and parameter set.
A Second Form of GetMethods( )
A second form of GetMethods( )
lets you specify various flags that filter the methods that are retrieved. It has this general form:
MethodInfo[ ] GetMethods(BindingFlags flags)
This version obtains only those methods that match the criteria that you specify.BindingFlags
is an enumeration. Here are several commonly used values:
DeclaredOnly
Retrieves only those methods defined by the specified class. Inherited methods are not included.Instance
Retrieves instance methods.NonPublic
Retrieves non-public methods.Public
Retrieves public methods.Static
Retrieves static methods.You can OR together two or more flags. In fact, minimally, you must include eitherInstance
or Static
with Public
or NonPublic
. Failure to do so will result in no methods being retrieved.
One of the main uses of the BindingFlags
form of GetMethods( )
is to enable you to obtain a list of the methods defined by a class without also retrieving the inherited methods. This is especially useful for preventing the methods defined by an object from being obtained. For example, try substituting this call toGetMethods( )
into the preceding program:
// Now, only methods declared by MyClass are obtained. MethodInfo[] mi = t.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
Reflecting on Fields and Properties
The behavior of Type.GetField()
and Type.GetFields()
is exactly similar to the above two methods, exceptType.GetField()
returns a reference of System.Reflection.MethodInfo
andType.GetFields()
returns a reference of a System.Reflection.MethodInfo
array. Similarly,Type.GetProperty()
and Type.GetProperties()
too.
The logic to display a type's properties is similar:
// GetFieldsPropertiesDemo.cs using System; using System.Reflection; namespace Reflection { class GetFieldsPropertiesDemo { static void Main() { // Get name of type Type t = typeof(Car); GetFields(t); GetProperties(t); Console.ReadLine(); } // Display field names of type. public static void GetFields(Type t) { Console.WriteLine("***** Fields *****"); FieldInfo[] fi = t.GetFields(); foreach (FieldInfo field in fi) Console.WriteLine("->{0}", field.Name); Console.WriteLine(""); } // Display property names of type. public static void GetProperties(Type t) { Console.WriteLine("***** Properties *****"); PropertyInfo[] pi = t.GetProperties(); foreach (PropertyInfo prop in pi) Console.WriteLine("->{0}", prop.Name); Console.WriteLine(""); } }}
Output
***** Fields ***** ->Color ***** Properties ***** ->Speed
Reflecting on Implemented Interfaces
GetInterfaces()
returns an array of System.Type
s! This should make sense given that interfaces are, indeed, types:
// GetInterfacesDemo.cs using System; using System.Reflection; namespace Reflection { class GetInterfacesDemo { static void Main() { // Get name of type Type t = typeof(Car); GetInterfaces(t); Console.ReadLine(); } // Display implemented interfaces. public static void GetInterfaces(Type t) { Console.WriteLine("***** Interfaces *****"); Type[] ifaces = t.GetInterfaces(); foreach (Type i in ifaces) Console.WriteLine("->{0}", i.Name); } } }
Output
***** Interfaces ***** ->ICar
Reflecting on Method Parameters and Return Values
To play with method parameters and return types, we first need to build a MethodInfo[]
array using the GetMethods()
function.
The MethodInfo
type provides the ReturnType
property and theGetParameters()
method for these very tasks.
using System; using System.Reflection; using System.Text; namespace Reflection { class GetParameterInfoDemo { static void Main() { // Get name of type Type t = typeof(Car); GetParametersInfo(t); Console.ReadLine(); } //Display Method return Type and paralmeters list public static void GetParametersInfo(Type t) { Console.WriteLine("***** GetParametersInfo *****"); MethodInfo[] mi = t.GetMethods(); foreach (MethodInfo m in mi) { // Get return value. string retVal = m.ReturnType.FullName; StringBuilder paramInfo = new StringBuilder(); paramInfo.Append("("); // Get params. foreach (ParameterInfo pi in m.GetParameters()) { paramInfo.Append(string.Format("{0} {1} ", pi.ParameterType, pi.Name)); } paramInfo.Append(")"); // Now display the basic method sig. Console.WriteLine("->{0} {1} {2}", retVal, m.Name, paramInfo); } Console.WriteLine(""); } } }
Output
***** GetParametersInfo ***** ->System.Int32 get_Speed () ->System.Void Accelerate (System.Int32 accelerateBy ) ->System.Boolean IsMoving () ->System.Double calculateMPG (System.Int32 startMiles System.Int32 endMiles Syst em.Double gallons ) ->System.String ToString () ->System.Boolean Equals (System.Object obj ) ->System.Int32 GetHashCode () ->System.Type GetType ()
Reflecting on Constructor
The GetConstractors()
function returns an array of ConstractorInfo
elements which we can use to get more class constructor information.
// GetConstractorInfoDemo.cs using System; using System.Reflection; namespace Reflection { class GetConstractorInfoDemo { static void Main() { // Get name of type Type t = typeof(Car); GetConstructorsInfo(t); Console.ReadLine(); } // Display method names of type. public static void GetConstructorsInfo(Type t) { Console.WriteLine("***** ConstructorsInfo *****"); ConstructorInfo[] ci = t.GetConstructors (); foreach (ConstructorInfo c in ci) Console.WriteLine(c.ToString () ); Console.WriteLine(""); } } }
Output
***** ConstructorsInfo ***** Void .ctor() Void .ctor(System.String, Int32)
Assembly Class
The System.Reflection
namespace provides a class calledAssembly
. We can use this Assembly
class to fetch information about the assembly and manipulate the provided assembly; this class allows us to load modules and assemblies at run time. TheAssembly
class contacts the PE file to fetch the metadata information about the assembly at runtime. Once we load the assembly using thisAssembly
class, we can search the type information within the assembly. It is also possible to create instances of types returned by theAssembly
class.
Dynamically Loading an Assembly
The Assembly
class provides the following methods to load an assembly at runtime:
Load()
: This static overloaded method takes the assembly name as input parameter and searches the given assembly name in the system.LoadFrom()
: This static overloaded method takes the complete path of an assembly, it will directly look into that particular location instead of searching in the system.GetExecutingAssembly()
: TheAssembly
class also provides another method to obtain the currently running assembly information using theGetExecutingAssembly()
methods. This method is not overloaded.GetTypes()
: TheAssembly
class also provides a nice feature called theGetTypes
method which allows you to obtain the details of all the types that are defined in the corresponding assembly.GetCustomAttributes()
: This static overloaded method gets the attributes attached to the assembly. You can also callGetCustomAttributes()
, specifying a second parameter, which is aType
object that indicates the attribute class in which you are interested.
// AssemblyDemo.cs class AssemblyDemo { static void Main() { Assembly objAssembly; // You must supply a valid fully qualified assembly name here. objAssembly = Assembly.Load("mscorlib,2.0.0.0,Neutral,b77a5c561934e089"); // Loads an assembly using its file name //objAssembly = Assembly.LoadFrom( // @"C:\Windows\Microsoft.NET\Framework\v1.1.4322\caspol.exe"); //this loads currnly running process assembly // objAssembly = Assembly.GetExecutingAssembly(); Type[] Types = objAssembly.GetTypes(); // Display all the types contained in the specified assembly. foreach (Type objType in Types) { Console.WriteLine(objType.Name.ToString()); } //fetching custom attributes within an assembly Attribute[] arrayAttributes = Attribute.GetCustomAttributes(objAssembly); // assembly1 is an Assembly object foreach (Attribute attrib in arrayAttributes) { Console.WriteLine(attrib.TypeId ); } Console.ReadLine(); }}
Late Binding
Late binding is a powerful technology in .NET Reflection which allows you to create an instance of a given type and invoke its members at runtime without having compile-time knowledge of its existence; this technique is also calleddynamic invocation. This technique is useful only when working with an object which is not available at compile time. In this technique, it is the developer's responsibility to pass the correct signature of the methods before invoking; otherwise, it will throw an error, whereas in early binding, the compiler verifies the method signature before calling the method. It is very important to take the right decision when to call and use and when not to use this because of performance issues. Using this technique has an impact on the performance of your application.
// LateBindingDemo.cs using System; using System.Reflection; namespace Reflection { class LateBindingDemo { static void Main() { Assembly objAssembly; // Loads an assembly objAssembly = Assembly.GetExecutingAssembly(); //get the class type information in which late bindig applied Type classType = objAssembly.GetType("Reflection.Car"); //create the instance of class using System.Activator class object obj = Activator.CreateInstance(classType); //get the method information MethodInfo mi = classType.GetMethod("IsMoving"); //Late Binding using Invoke method without parameters bool isCarMoving; isCarMoving= (bool) mi.Invoke(obj, null); if (isCarMoving) { Console.WriteLine("Car Moving Status is : Moving"); } else { Console.WriteLine("Car Moving Status is : Not Moving"); } //Late Binding with parameters object[] parameters = new object[3]; parameters[0] = 32456;//parameter 1 startMiles parameters[1] = 32810;//parameter 2 end Miles parameters[2] = 10.6;//parameter 3 gallons mi = classType.GetMethod("calculateMPG"); double MilesPerGallon; MilesPerGallon= (double ) mi.Invoke(obj, parameters); Console.WriteLine("Miles per gallon is : " + MilesPerGallon); Console.ReadLine(); } } }
Output
Car Moving Status is : Not Moving Miles per gallon is : 33.3962264150943
Reflection Emit
Reflection emit supports dynamic creation of new types at runtime. You can define an assembly to run dynamically or to save itself to disk, and you can define modules and new types with methods that you can then invoke.
Conclusion
Reflection in .NET is huge. Covering an entire API is not possible in this article. However, learning one part of it will give you a complete understanding ofReflection in .NET.
Thanks for reading my article. I hope you enjoyed it very much.
- Reflection in .net
- Reflection in .NET
- Java Reflection in Action
- reflection in java application
- Reflection in Javascript
- .Net Reflection机制
- Introduction to .NET Reflection
- .Net Reflection机制
- .Net Reflection 浅析
- Reflection Using Cg in OpenGL
- mechanisms for reflection in AX
- JNI and Reflection in Android
- java 反射 Reflection in Java
- .NET Reflection optimization 反射优化
- .NET反射Reflection机制学习
- Reflection in Actionscript 3.0/Flex 2
- A design & implementation of reflection in C++
- 读书笔记Java Reflection In Action 157页
- Servlet核心介绍之一
- HTML5之学习笔记一
- 总结-2012-3-18
- Android上封装的一个音频工具类
- 给source insight添加.cc的C++文件后缀识别
- Reflection in .NET
- 苹果正式关闭ios 5.0.1的SHSH固件验证
- JavaScript笔记之用链接对用户进行重定向
- 昂,弄了Vmware虚拟机和笔记本无线上网桥接的问题 弄了几个小时 找了一个文章 分享下
- 第十八天(C++代码重用III)
- Android开机动画过程
- 桌面图标任意摆
- log4j 配置详解
- Android异步加载图像小结