reflection leveraging the power of metadata
Post on 22-Dec-2015
219 views
TRANSCRIPT
ReflectionReflection
Leveraging the Power of MetadataLeveraging the Power of Metadata
www.csse.monash.edu.au/courseware/cse5510/Lectures/lecture3.ppt
ObjectivesObjectives
Provide an introduction to .NET Provide an introduction to .NET ReflectionReflection
Explain how applications can use Explain how applications can use Reflection to explore type information Reflection to explore type information and how they can build types at and how they can build types at runtimeruntime
ContentsContents
Section 1: OverviewSection 1: OverviewSection 2: Exploring MetadataSection 2: Exploring MetadataSection 3: Detail InformationSection 3: Detail InformationSection 4: Building Types at RuntimeSection 4: Building Types at RuntimeSection 5: Putting it togetherSection 5: Putting it togetherSummarySummary
Section 1: OverviewSection 1: Overview
.NET Compile-Execution Cycle.NET Compile-Execution Cycle .NET Reflection Core Concepts.NET Reflection Core Concepts
Execution modelExecution model
Cobol VB C++ C#
CIL code(+ metadata)
Loader/verifierLoader/verifier
Managed Code
Uncompiledmethod call
ExecutionExecution
Language compilersLanguage compilers
.NET languages
JIT compilerJIT compiler
.Net Architecture.Net Architecture
Base Class Library
Common Language Specification
Common Language Runtime
Data and XML
VB C++ C#V
isual S
tud
io.N
ET
Web Services,ASP.Net
JScript …
User InterfaceWinForms
All types in the CLR are self-All types in the CLR are self-describing describing – CLR provides a reader and writer for
type definitions• System.Reflection & System.Reflection.emit
– You can ‘read’ programs – You can map between type systems – You can interrogate objects and types
inside a running program
Reflection OverviewReflection Overview
.NET Reflection Core Concepts.NET Reflection Core Concepts
MetadataMetadata– Single location for type information and code– Code is literally contained within type
information– Every .NET object can be queried for its type– Types' metadata can be explored with
Reflection Dynamic Type SystemDynamic Type System
– Highly dynamic and language independent– Types may be extended and built at run-time– Allows on-the-fly creation of assemblies– .NET Compilers use .NET to emit .NET code
Reflection is fundamental to the CLRReflection is fundamental to the CLR
RMI
Proxies
Serialization
Code Generation
Analysis, Documentation
JVM
COM
Directory
DBMS
XML
Metadata usesMetadata uses
Allows type developed in a PL to be Allows type developed in a PL to be used by code in other PLused by code in other PL
GC uses to traverse objectsGC uses to traverse objectsSerialization (essential for Web Serialization (essential for Web
Services)Services) IDE (e.g. IntelliSense)IDE (e.g. IntelliSense)
Section 2: Exploring MetadataSection 2: Exploring Metadata
Who are you?Who are you?What are you?What are you?Anything special about you?Anything special about you?Now tell me what you have!Now tell me what you have!Types and InstancesTypes and Instances
Type ReflectionType Reflection
Object
IEnquire
IPrint
IXfer
Account
Savings
Savings.BaseType ==Account
Savings.BaseType.BaseType == Object
Ixfer.BaseType == null
Account.IsSubClassof(IEnquire) == false
Savings.IsSubClassof(Account) == true
Savings.GetInterfaces() == { Iprint, Ixfer, Ienquire }
Ienquire.IsAssignableFrom(Savings) == true
Reflection and the CLR type systemReflection and the CLR type system
System.Object
EventInfoPropertyInfoFieldInfoMethodBaseSystem.Type
ParameterInfoMemberInfoModuleAssembly
MethodInfo ConstructorInfo
MetaData: Type Info at RuntimeMetaData: Type Info at Runtime[serializable]public class Person : { public event OnSaveChange onsv; public Date DOB; public string FirstName; public string LastName; public string Name { get { return FirstName + " " + LastName; } } public Person(string First,string Last) { FirstName=First;LastName=Last; } public bool Save() { System.Type t = this.GetType(); foreach( FieldInfo f in t.GetFields() ) { ... } }
System.Type
Attributes
Fields
Properties
Constructors
Methods
Events
Parameters
Traverse every element in an assemblyTraverse every element in an assembly
Using System.Reflection;
Public static void WalkAssembly(String assemblyName)
{
Assembly assembly = Assembly.Load (assemblyName);
foreach (Module module in assembly.GetModules())
foreach (Type type in module.GetTypes())
foreach (MemberInfo member in type.GetMembers())
Console.WriteLine (“{0}.{1}”, type, member.Name;
}
SerializationSerialization
Save state of an object on disk or send to a Save state of an object on disk or send to a stream:stream:
public class Point : {public double x;public double y;public double length; // computed from x, y
};
SolutionsSolutions
Inherit from a base type:Inherit from a base type:class Point : Serializable { … }but …– base type does not know derived type– requires multiple inheritance
Java solution:Java solution:class Point implements Serializable { … }but …– method granularity– customization requires full rewrite of
WriteObject, ReadObject
Solution: AttributesSolution: Attributes
[Serializable]public class Point : {
public double x;public double y;[NonSerialized]public double length; // computed from x, y
};
Rotor Serialization EngineRotor Serialization Engine
protected virtual void WriteMember(String memberName, Object data) { if (data==null) { WriteObjectRef(data, memberName, typeof(Object)); return; } Type varType = data.GetType(); if (varType == typeof(Boolean)) { WriteBoolean(Convert.ToBoolean(data), memberName); } else if (varType == typeof(Char)) { WriteChar(Convert.ToChar(data), memberName); } else if (varType == typeof(Byte)) { WriteByte(Convert.ToByte(data), memberName); } ...} ... else { if (varType.IsArray) { WriteArray(data, memberName, varType); } else if (varType.IsValueType) { WriteValueType(data, memberName, varType); } else { WriteObjectRef(data, memberName, varType); }}
Reflection EmitReflection Emit
– Assemblybuilder– ConstructorBuilder– CustomAttributeBu
ilder– EnumBuilder– EventBuilder– FieldBuilder– ILGenerator– Label
– LocalBuilder– MethodBuilder– ModuleBuilder– ParameterBuilder– PropertyBuilder– TypeBuilder
Abstractions correspond closely to the CTS that underlies Abstractions correspond closely to the CTS that underlies the CLR:the CLR:
Who are you?Who are you?
Accessing meta-data: System.Object.GetType()Accessing meta-data: System.Object.GetType()– All .NET classes (implicitly) inherit System.Object– Available on every .NET class; simple types too
Explicit language support for type meta-dataExplicit language support for type meta-data– C#, JScript.NET: typeof(…)– VB.NET: If TypeOf … Is … Then …
Determining Type IdentityDetermining Type Identity– Types have unique identity across any assembly– Types can be compared for identity
• if (a.GetType() == b.GetType()) { … };
System.TypeSystem.Type
Access to meta-data for any .NET typeAccess to meta-data for any .NET typeReturned by System.Object.GetType()Returned by System.Object.GetType()Allows drilling down into all facets of a Allows drilling down into all facets of a
typetype– Category: Simple, Enum, Struct or Class– Methods and Constructors, Parameters
and Return– Fields and Properties, Arguments and
Attributes– Events, Delegates and Namespaces
What are you?What are you?
Value, Interface or Class?Value, Interface or Class?– IsValueType, IsInterface, IsClass
Public, Private or Sealed ?Public, Private or Sealed ?– IsNotPublic, IsSealed
Abstract or Implementation?Abstract or Implementation?– IsAbstract
Covers all possible properties of a Covers all possible properties of a managed typemanaged type
Very intuitive API, no "Parameter Hell"Very intuitive API, no "Parameter Hell"
Anything special about you?Anything special about you?
Special Memory Layout?Special Memory Layout?– IsAutoLayout– IsExplicitLayout– IsLayoutSequential
COM Objects?COM Objects?– IsCOMObject
More… More… – IsUnicodeClass
– IsSpecialName, etc.
Now tell me what you have!Now tell me what you have!
Finding and Exploring MembersFinding and Exploring Members– MemberInfo: GetMembers(), FindMembers()
Exploring Fields and PropertiesExploring Fields and Properties– FieldInfo: GetFields(), PropertyInfo:
GetProperties() Exploring Constructors, Methods and Exploring Constructors, Methods and
EventsEvents– GetConstructors(), GetMethods(), GetEvents()
Exploring attributes, determining Exploring attributes, determining implemented interfaces, enumerating implemented interfaces, enumerating nested types, …nested types, …
Summary: Everything you may ever want Summary: Everything you may ever want to knowto know
Type and InstancesType and Instances
Type Safety First! Type checking at Type Safety First! Type checking at runtimeruntime– C#: if (o is Customer) { … }– VB: If TypeOf o Is Customer Then … End If
Dynamic Invocation through Dynamic Invocation through ReflectionReflection– Support for late binding
•MethodInfo.Invoke()•FieldInfo.SetValue()•PropertyInfo.SetValue()
Section 3: Detail InformationSection 3: Detail Information
MemberInfoMemberInfoFieldInfo, PropertyInfoFieldInfo, PropertyInfoConstructorInfo, MethodInfoConstructorInfo, MethodInfo
MemberInfoMemberInfoBase class for all "member" element descriptionsBase class for all "member" element descriptions
– Fields, Properties, Methods, etc.Provides member kind, name and declaring classProvides member kind, name and declaring class
MemberInfo
MethodBase ParameterInfo FieldInfo EventInfo PropertyInfo
MethodInfo ConstructorInfo
FieldInfo, PropertyInfoFieldInfo, PropertyInfo
FieldInfoFieldInfo– Field data type and attributes– Static or Instance field, protection level– Can set value through reflection
• Provides low-level, direct access with SetValueDirect()
PropertyInfoPropertyInfo– Property type and attributes– Test methods for readability, writeability– "get" and "set" MethodInfo– Indexer ParameterInfo– Can invoke "set" and "get" through
Reflection
MethodInfo, ConstructorInfoMethodInfo, ConstructorInfo
MethodInfoMethodInfo– Return type and attributes– List of all parameters as ParameterInfo
array– Detail implementation information
through flag-field– Can invoke method through Reflection
ConstructorInfoConstructorInfo– Same features as MethodInfo, just for
constructors
AttributesAttributes
Custom attributes are the killer-app for Reflection!Custom attributes are the killer-app for Reflection! Attributes enable declarative behaviorAttributes enable declarative behavior Attributes allow data augmentationAttributes allow data augmentation
[dbcolumn("Address1")] string Street;[dbcolumn("Postcode")] string ZIP;
[serializable]class Person{ ...
Map fields to database columns with
FieldInfo.GetCustomAttributes()
Mark class as serializable Type.GetCustomAttributes()
Custom AttributesCustom Attributes
[BugFix(121,“GA","01/03/05")][BugFix(121,“GA","01/03/05")][BugFix(107,“GA","01/04/05", [BugFix(107,“GA","01/04/05",
Comment="Fixed off by one errors")]Comment="Fixed off by one errors")]public class MyMath {public class MyMath {
public double DoFunc1(double param1) {public double DoFunc1(double param1) {return param1 + return param1 +
DoFunc2(param1); }DoFunc2(param1); }
public double DoFunc2(double param1) {public double DoFunc2(double param1) {return param1 / 3; } return param1 / 3; }
}}
Definining a Custom AttributeDefinining a Custom Attribute
public class BugFixAttribute : System.Attribute {public class BugFixAttribute : System.Attribute {
public BugFixAttribute(int bugID, string public BugFixAttribute(int bugID, string programmer, string date) {programmer, string date) {this.bugID = bugID;this.bugID = bugID;this.programmer = programmer;this.programmer = programmer;this.date = date;this.date = date;
}}
//// Named parameters are implemented as Named parameters are implemented as properties: properties:
public string Comment {public string Comment {get { return comment; }get { return comment; }set { comment = value; }set { comment = value; }
} }} }
Using AttributesUsing Attributes
MyMath mm = new MyMath( );MyMath mm = new MyMath( );Console.WriteLine("Calling DoFunc(7). Result: {0}", mm.DoFunc1(7));Console.WriteLine("Calling DoFunc(7). Result: {0}", mm.DoFunc1(7));// get the member information and use it to retrieve the custom attributes// get the member information and use it to retrieve the custom attributes
System.Reflection.MemberInfo inf = typeof(MyMath);System.Reflection.MemberInfo inf = typeof(MyMath);BugFixAttribute[] attributes = BugFixAttribute[] attributes =
(BugFixAttribute[])inf.GetCustomAttributes(typeof(BugFixAttribute), (BugFixAttribute[])inf.GetCustomAttributes(typeof(BugFixAttribute), false);false);
// iterate through the attributes, retrieving the properties// iterate through the attributes, retrieving the propertiesforeach(BugFixAttribute attribute in attributes) {foreach(BugFixAttribute attribute in attributes) { Console.WriteLine("\nBugID: {0}", attribute.BugID);Console.WriteLine("\nBugID: {0}", attribute.BugID); Console.WriteLine("Programmer: {0}", attribute.Programmer);Console.WriteLine("Programmer: {0}", attribute.Programmer); Console.WriteLine("Date: {0}", attribute.Date);Console.WriteLine("Date: {0}", attribute.Date); Console.WriteLine("Comment: {0}", attribute.Comment);Console.WriteLine("Comment: {0}", attribute.Comment);}}
Output:Output: Calling DoFunc(7). Result: 9.33Calling DoFunc(7). Result: 9.33 BugID: 121 Programmer: GA Date: 01/03/05 Comment:BugID: 121 Programmer: GA Date: 01/03/05 Comment: BugID: 107 Programmer: GA Date: 01/04/05 Comment: Fixed off by one BugID: 107 Programmer: GA Date: 01/04/05 Comment: Fixed off by one
errors errors
Dynamic Method InvocationDynamic Method Invocation
Type theMathType = Type.GetType("System.Math");Type theMathType = Type.GetType("System.Math");Object theObj = Object theObj =
Activator.CreateInstance(theMathType); Activator.CreateInstance(theMathType); Type[] paramTypes = new Type[] Type[] paramTypes = new Type[]
{ Type.GetType("System.Double")};{ Type.GetType("System.Double")};
MethodInfo CosineMeth = MethodInfo CosineMeth = theMathType.GetMethod("Cos", theMathType.GetMethod("Cos", paramTypes);paramTypes);
Object[] parameters = new Object[1];Object[] parameters = new Object[1];parameters[0] = 45;parameters[0] = 45;Object returnVal = Object returnVal =
CosineMeth.Invoke(theObj, parameters);CosineMeth.Invoke(theObj, parameters);
Loop unrollingLoop unrolling
public int DoSumLooping(int n) public int DoSumLooping(int n) {{
int result = 0;int result = 0;
for(int i = 1; i <= n; i++)for(int i = 1; i <= n; i++)
result += i;result += i;
return result;return result;
} }
Loop unrollingLoop unrolling
public double DoSum(int n) {public double DoSum(int n) {if (adder == null)if (adder == null)
GenerateCode(n);GenerateCode(n);// call the method through the interface// call the method through the interfacereturn (adder.ComputeSum( ));return (adder.ComputeSum( ));
}}public void GenerateCode(int n) {public void GenerateCode(int n) {
Assembly theAssembly = EmitAssembly(n);Assembly theAssembly = EmitAssembly(n);adder = (IComputer) adder = (IComputer) theAssembly.CreateInstance(“UnrolledSum");theAssembly.CreateInstance(“UnrolledSum");
} }
Create the AssemblyCreate the Assembly
private Assembly EmitAssembly(int n) {private Assembly EmitAssembly(int n) {assemblyName = new AssemblyName( ); assemblyName = new AssemblyName( );
assemblyName.Name = "DoSumAssembly";assemblyName.Name = "DoSumAssembly";AssemblyBuilder newAssembly = AssemblyBuilder newAssembly =
Thread.GetDomain().DefineDynamicAssemblThread.GetDomain().DefineDynamicAssembly(assemblyName, y(assemblyName, AssemblyBuilderAccess.Run);AssemblyBuilderAccess.Run);ModuleBuilder newModule = ModuleBuilder newModule = newAssembly.DefineDynamicModule("Sum");newAssembly.DefineDynamicModule("Sum");TypeBuilder myType = TypeBuilder myType = newModule.DefineType( “UnrolledSum", newModule.DefineType( “UnrolledSum", TypeAttributes.Public);TypeAttributes.Public);
myType.AddInterfaceImplementation( typeof(IComputermyType.AddInterfaceImplementation( typeof(IComputer));));
Create the AssemblyCreate the Assembly
// Define a method on the type to call. Pass an// Define a method on the type to call. Pass an // array that defines the types of the parameters,// array that defines the types of the parameters, // the type of the return type, the name of the// the type of the return type, the name of the // method, and the method attributes.// method, and the method attributes. Type[] paramTypes = new Type[0];Type[] paramTypes = new Type[0]; Type returnType = typeof(int);Type returnType = typeof(int); MethodBuilder simpleMethod = MethodBuilder simpleMethod =
myType.DefineMethod( "ComputeSum", myType.DefineMethod( "ComputeSum", MethodAttributes.Public | MethodAttributes.Public | MethodAttributes.Virtual, returnType, MethodAttributes.Virtual, returnType, paramTypes); paramTypes);
Generating IL codeGenerating IL code
ILGenerator generator = simpleMethod.GetILGenerator( ); ILGenerator generator = simpleMethod.GetILGenerator( ); // Emit the IL// Emit the IL// Push zero onto the stack. For each 'i‘ less than 'theValue',// Push zero onto the stack. For each 'i‘ less than 'theValue',// push 'i' onto the stack as a constant// push 'i' onto the stack as a constant// add the two values at the top of the stack.// add the two values at the top of the stack.// The sum is left on the stack.// The sum is left on the stack.generator.Emit(OpCodes.Ldc_I4, 0);generator.Emit(OpCodes.Ldc_I4, 0);for (int i = 1; i <= theValue; i++) {for (int i = 1; i <= theValue; i++) {
generator.Emit(OpCodes.Ldc_I4, i);generator.Emit(OpCodes.Ldc_I4, i);generator.Emit(OpCodes.Add);generator.Emit(OpCodes.Add);
}}// return the value// return the valuegenerator.Emit(OpCodes.Ret);generator.Emit(OpCodes.Ret);
computeSumInfo = typeof(IComputer).GetMethod("ComputeSum");computeSumInfo = typeof(IComputer).GetMethod("ComputeSum");myType.DefineMethodOverride(simpleMethod, computeSumInfo);myType.DefineMethodOverride(simpleMethod, computeSumInfo);
// Create the type.// Create the type.myType.CreateType( );myType.CreateType( );returnreturn newAssembly;newAssembly;}}
Generated IL CodeGenerated IL Code
Ldc_I4 0Ldc_I4 0Ldc_I4 1Ldc_I4 1AddAddLdc_I4 2Ldc_I4 2AddAddLdc_I4 3Ldc_I4 3AddAddLdc_I4 4Ldc_I4 4AddAddLdc_I4 5Ldc_I4 5AddAddRetRet
PerformancePerformance
Output:Output:
Sum of (2000) = 2001000 Looping. Sum of (2000) = 2001000 Looping. Elapsed ms: 11468.75 for 1000000 Elapsed ms: 11468.75 for 1000000 iterationsiterations
Sum of (2000) = 2001000 UnrolledLoop. Sum of (2000) = 2001000 UnrolledLoop. Elapsed ms: 406.25 for 1000000 Elapsed ms: 406.25 for 1000000 iterations iterations
The Bigger pictureThe Bigger picture
Types know their Module, Modules know their Types know their Module, Modules know their typestypes
Modules know their Assembly and vice versaModules know their Assembly and vice versa Code can browse and search its entire contextCode can browse and search its entire context
Assembly
Module Module Module
Class StructConstructor
Method
Method
Field
Class
Interface
Class
Delegate
Class
Interface
Interface
The Unmanaged Spy: Metadata APIThe Unmanaged Spy: Metadata API
Unmanaged (COM) Version of Unmanaged (COM) Version of ReflectionReflection
Used by VisualStudio.NET and Used by VisualStudio.NET and CompilersCompilers
Full Access to all Reflection Full Access to all Reflection Information for ToolsInformation for Tools
Fully documented in the "Tool Fully documented in the "Tool Developer's Guide"Developer's Guide"
Buddy: Assembly Metadata APIBuddy: Assembly Metadata API– Reads/writes Assembly Manifests
Section 4: Building Types at RuntimeSection 4: Building Types at Runtime
Introducing System.Reflection.EmitIntroducing System.Reflection.EmitWhy? Some scenarios Why? Some scenarios Dynamic Modules and AssembliesDynamic Modules and AssembliesCreating Types and ClassesCreating Types and ClassesWriting ILWriting IL
Introducing System.Reflection.EmitIntroducing System.Reflection.Emit
Full representation of physical Full representation of physical structurestructure
Allows building modules and Allows building modules and assemblies at runtimeassemblies at runtime– Transient code only used at runtime– Persistent code for reuse
Create classes, types and emit ILCreate classes, types and emit ILUsed by .NET compilers to build .NET Used by .NET compilers to build .NET
appsapps
Why? Some Scenarios…Why? Some Scenarios…
Build classes dynamically from script-like Build classes dynamically from script-like codecode– ASP.NET, Regular Expressions do just that !
Generate code from visual development Generate code from visual development toolstools– e.g. build interfaces, base classes from UML
Create dynamic wrappers for existing codeCreate dynamic wrappers for existing code Transfer code-chunks to remote machinesTransfer code-chunks to remote machines
– Distributed processing scenarios (like SETI@home)
Building AssembliesBuilding Assemblies
System.Reflection.Emit.AssemblyBuildSystem.Reflection.Emit.AssemblyBuilderer
Dynamically create new assembliesDynamically create new assemblies– Create manifest and resources– Add modules– Specify security requirements
Can be persisted as files or held in Can be persisted as files or held in memorymemory
Act and behave like any other Act and behave like any other assemblyassembly
Building ModulesBuilding Modules
System.Reflection.Emit.ModuleBuilderSystem.Reflection.Emit.ModuleBuilderModules contain types, classes and Modules contain types, classes and
codecodeAllows creating fully functional Allows creating fully functional
modules with codemodules with codeCan associate source codeCan associate source codeEmit debug symbolsEmit debug symbolsActs like any module created by Acts like any module created by
any .NET compilerany .NET compiler
Writing ILWriting IL
Emit accepts IL (Intermediate Language) Emit accepts IL (Intermediate Language) code code
Same code as emitted by C#, VB.NET, Same code as emitted by C#, VB.NET, Eiffel#Eiffel#
IL is optimized and translated into machine IL is optimized and translated into machine codecode
Reflection.Emit puts you "on-par"Reflection.Emit puts you "on-par"– Same backend as .NET compilers– Same access to code-generation– Languages are mostly scanners and parsers
For more info see System.CodeDOMFor more info see System.CodeDOM
Section 5: Putting It TogetherSection 5: Putting It Together
VisualStudio.NET and ReflectionVisualStudio.NET and ReflectionWhat ASP+ really does with a pageWhat ASP+ really does with a page
VisualStudio.NET and ReflectionVisualStudio.NET and Reflection
Component Class
Description
DefaultValue
Help
Localizable
ReadOnly
ComponentModel Attributes
Toolbox
Properties Window
Designers
Help
What ASP.NET does with a PageWhat ASP.NET does with a Page
<%Page codebehind="pg"%><html><body> <asp:label/> <asp:textbox/></html></body>
ASP.NET compiler
Reflection
Page Assembly
IIS
ASP.NET runtime
1 2
2a 3
file exists? assembly exists, same timestamp?
no? compile run
class pg : Page{ ... }
SummarySummary
Reflection = System.Type + GetType()Reflection = System.Type + GetType()Explore Type Information at RuntimeExplore Type Information at RuntimeEnables Attribute-Driven Enables Attribute-Driven
ProgrammingProgrammingUse Emit Classes to Produce .NET Use Emit Classes to Produce .NET
AssembliesAssembliesBottom Line: Fully Self-Contained Bottom Line: Fully Self-Contained
Structural ModelStructural Model