190 likes | 598 Views
Reflection. .NET Support for Reflection. What is Reflection. Reflection: the process by which a program can observe and modify its own structure and behavior at runtime. What kind of tasks are specific to Reflection:
E N D
Reflection .NET Support for Reflection
What is Reflection • Reflection: the process by which a program can observe and modify its own structure and behavior at runtime. • What kind of tasks are specific to Reflection: • Inspection: analyzing objects and types to gather information about their definition and behavior. • Typically this is done with little or no prior knowledge about them. (For instance, in the .NET Framework, everything inherits from System.Object and an object-typed reference is the typical starting point for reflection.) • Manipulation: uses the information gained through inspection to invoke code dynamically, create new instances of discovered types, or even restructure types and objects on the fly • Manipulating types and objects at run time incurs a performance penalty when compared to the equivalent operations done statically in the source code ! • Reflective capabilities need language and compiler-support (vezi exemplul de la Reflection Pattern – curs sapt 6)
Introduction to .NET Reflection • System.Reflection: namespace containing several types that allow to reflect over (parse) the metadata tables in assemblies • What can you do by reflection ? • Enumerate modules and types of an assembly; • For each type, obtain its base type, implemented interfaces, fields, methods, properties, events • Create instances of types, dynamically invoke methods • What you cannot do by reflection: • Get information from the reference metadata tables • You could parse the assembly file directly to extract this type of information (as ILDASM does)
Where to use reflection ? • Class libraries that need to understand a type’s definition: typical example – Serialization • Late binding: the types and methods an application uses are not known at compile time; • example: application gets at runtime the names of an assembly and the name of a type contained in it. The application loads the assembly, constructs an instance of the type and calls methods on it.
The Reflection Logical HierarchyClasses that implement metaobjects Class Type is defined in the namespace System. All others are defined in System.Reflection
Reflecting Over an Assembly’s Types public class Reflector { public static void ReflectOnAssembly(Assembly assem) { WriteLine(0, "Assembly: {0}", assem); // Find Modules foreach (Module m in assem.GetModules()) { WriteLine(1, "Module: {0}", m); // Find Types foreach (Type t in m.GetTypes()) { WriteLine(2, "Type: {0}", t); // Find Members foreach (MemberInfo mi in t.GetMembers()) WriteLine(3, "{0}: {1}", mi.MemberType, mi); } } } … } Example: starting from an Assembly metaobject, we can determine the modules that it contains. For each module, we can determine the types defined there. C# [Richter] – ex. Chap. 20
Get a reference to the executing assembly Determines which assembly contains the method that’s making the call and returns its metaobject using System; using System.Reflection; class App { static void Main() { Assembly assem = Assembly.GetExecutingAssembly(); Reflector.ReflectOnAssembly(assem); } } public class Reflector { … } C# [Richter] – ex. Chap. 20
Explicitly Loading Assemblies using System; using System.Reflection; class App { static void Main(string[] args) { Console.WriteLine("Loading assembly: {0}",args[0]); Assembly a = Assembly.LoadFile(args[0]); Reflector.ReflectOnAssembly(a); } } public class Reflector { … } Loads an assembly specified by the name of its file. The assembly is loaded as a ”data file” C#
Obtaining a Reference to a System.Type Object • Reflection can be used to learn about types or to manipulate objects using information available only at runtime, not at compile time • How to obtain a reference to a System.Type object: • From a System.Object : defines a method GetType which determines the type of the specified object and returns a reference to its metaobject • From System.Type: defines a static method GetType(String Name) which checks the calling assembly for the defined type and returns a reference to its metaobject • From System.Module as presented in the example before • What can you do with this reference: • You can query the type’s properties: • Flags: IsPublic, IsAbstract, IsClass. • Names: Name, Assembly, FullName, Module • BaseType • Interfaces that are implemented by this type • You can reflect over the type’s members : • GetConstructors(), GetEvents(), GetFields(), GetMembers(), GetMethods(), GetProperties() • You can invoke its methods or set values to its properties • InvokeMember()
Exampledemonstrates that Object.GetType returns the runtime type of the current instance // GetTypeExample.jsl import System.*; public class MyBaseClass extends Object { } //MyBaseClass public class MyDerivedClass extends MyBaseClass { } //MyDerivedClass public class Test { public static void main(String[] args) { MyBaseClass myBase = new MyBaseClass(); MyDerivedClass myDerived = new MyDerivedClass(); Object o = myDerived; MyBaseClass b = myDerived; Console.WriteLine("mybase: Type is {0}", myBase.GetType()); Console.WriteLine("myDerived: Type is {0}", myDerived.GetType()); Console.WriteLine("object o = myDerived: Type is {0}", o.GetType()); Console.WriteLine("MyBaseClass b = myDerived: Type is {0}", b.GetType()); } //main } //Test This code produces the following output: mybase: Type is MyBaseClass myDerived: Type is MyDerivedClass object o = myDerived: Type is MyDerivedClass MyBaseClass b = myDerived: Type is MyDerivedClass J# [MSDN Library]
Reflecting over a type’s members • Members of a type: Fields, constructors, methods, properties, events, and nested types. • The FCL contains a type called System.Reflection.MemberInfo. • Can be obtained from Type: method GetMembers() returns an array of MemberInfo • Table shows some properties and methods offered by the MemberInfo type. These properties and methods are common to all type members.
MemberInfo is abstract GetMembers() method in Type returns an array of elements that are of the concrete subtypes Type offers also specific methods: GetFields(), GetConstructors(), GetMethods(), GetProperties(), GetEvents() Hierarchy of the reflection types derived from MemberInfo
// TypeGetMembersExample.jsl class MyClass { public int myInt = 0; public String myString = null; public MyClass() { } //MyClass public void Myfunction() { } //Myfunction private void MySecret() { } //MySecret } //MyClass class Type_GetMembers { public static void main(String[] args) { MyClass myObject = new MyClass(); MemberInfo myMemberInfo[]; // Get the type of 'MyClass'. Type myType = myObject.GetType(); // Get the info related to all public member's of 'MyClass'. myMemberInfo = myType.GetMembers(); Console.WriteLine( "\nThe members of class '{0}' are :\n", myType); for (int i = 0; i < myMemberInfo.length; i++) { // Display name and type of the concerned member. Console.WriteLine("'{0}' is a {1}", myMemberInfo[i].get_Name(), myMemberInfo[i].get_MemberType()); } } //main } //Type_GetMembers Exampledemonstrates how to retrieve informations about a type’s members J# [MSDN Library]
Selecting kinds of reflected members • GetMembers methods can take a BindingFlags parameter: • IgnoreCase: Search using case-insensitivity. • DeclaredOnly: Only search members on the declared type. (Ignore inherited members.) • Instance: Search instance members. • Static: Search static members. • Public: Search public members. • NonPublic: Search nonpublic members. • FlattenHierarchy: Search static members defined by base types. • Code Acess Security and Reflection • Reflection makes it possible to bind to a nonpublic member and invoke the member, allowing application code a way to access private members that a compiler would normally prohibit the code from accessing. • However, reflection uses Code Access Security to ensure that its power isn’t abused or exploited. • Code with the appropriate System.Security.Permissions.ReflectionPermission can have access to the public, protected, and even private members of any loaded Type. • Security ReflectionPermissions in .NET can be set/enforced at assembly and/or type level
class Type_GetMembers { public static void main(String[] args) { try { MyClass myObject = new MyClass(); MemberInfo myMemberInfo[]; // Get the type of 'MyClass'. Type myType = myObject.GetType(); // Get the info related to all public+private member's of 'MyClass'. BindingFlags bf = BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static; myMemberInfo = myType.GetMembers(bf); Console.WriteLine("\nThe members of class '{0}' are :\n", myType); for (int i = 0; i < myMemberInfo.length; i++) { // Display name and type of the concerned member. Console.WriteLine("'{0}' is a {1}", myMemberInfo[i].get_Name(), myMemberInfo[i].get_MemberType()); } } catch (SecurityException e) { Console.WriteLine("Exception : " + e.get_Message()); } } //main } //Type_GetMembers Exampledemonstrates how to retrieve private information J# [MSDN Library]
Creating an Instance of a Type • Once you have a reference to a Type object, there are several mechanisms to create an instance of this type: • System.Activator: defines several overloaded CreateInstance method that get as parameters a Type object or a string that identifies the type. Creates an instance of the specified type using the constructor that best matches the specified parameter. Returns a reference to the new created Object • System.Reflection.ConstructorInfo: defines several overloaded Invoke method that invokes the constructor reflected by this instance. Returns an instance of the class associated with the constructor. • Special cases: • System.Array: static CreateInstance method in Array
Calling a Type’s Members • InvokeMember method in Type • Several overloaded versions; the maximum of parameters are: public Object InvokeMember( String name, // Name of member BindingFlags invokeAttr, // How to look up members Binder binder, // How to match members and arguments Object target, // Object to invoke member on or null if it is a static member Object[] args, // Arguments to pass to method CultureInfo culture); // Culture used by some binders • Internally, InvokeMember performs two operations: • Binding: select the appropriate member to be called • Invoking: actually invokes the member • invokeAttr: A bitmask comprised of one or more BindingFlags that specify how the search is conducted. The access can be one of the BindingFlags such as Public, NonPublic, Private, CreateInstance, InvokeMethod, GetField, SetField, DeclaredOnly, ExactBinding, etc. The type of lookup need not be specified. If the type of lookup is omitted, BindingFlags.Public| BindingFlags.Instance will apply. • Binder: A Binder object that defines a set of properties and enables binding, which can involve selection of an overloaded method, coercion of argument types, and invocation of a member through reflection. If it is not specified or null, the DefaultBinder is used.
Bind once, invoke multiple times • Every time you call InvokeMember, it must bind to a particular member and then invoke it. • Consequence: Having the binder select the right member each time you want to invoke a member is time-consuming. So if you plan on accessing a member frequently, you’re better off binding to the desired member once and then accessing that member as often as you want. • You bind to a member (without invoking it) by calling one of the following Type’s methods: GetFields, GetConstructors, GetMethods, GetProperties, GetEvents methods, or any similar method. • All these methods return references to objects whose type offers methods to access the specific member directly: • FieldInfo: GetValue, SetValue • ConstructorInfo: Invoke • MethodInfo: Invoke • PropertyInfo: GetValue, SetValue • EventInfo: AddEventHandler, RemoveEventHandler
// InvokeMethod.jsl import System.*; import System.Reflection.*; class MyClass { public int myInt = 0; public String myString = null; public MyClass() { } //MyClass public void MyFunction() { Console.WriteLine("My function"); } //Myfunction private void MySecret() { Console.WriteLine("My secret"); } } //MyClass class TestInvokeMethod { public static void main(String[] args) { // get somehow the Type metaobject Type myType = Type.GetType ("MyClass"); //create instance obj Object obj = Activator.CreateInstance(myType); // bind to method MyFunction MethodInfo mi = myType.GetMethod("MyFunction"); // invokes MyFunction on obj if (mi!=null) mi.Invoke(obj, null); mi = myType.GetMethod("MySecret"); if (mi!=null) mi.Invoke(obj, null);} } //main } Exampledemonstrates how to create an instance of a type and call it’s methods J#