reflection leveraging the power of metadata

54
Reflectio Reflectio n n Leveraging the Power of Leveraging the Power of Metadata Metadata www.csse.monash.edu.au/courseware/cse5510/Lectures/ lecture3.ppt

Post on 22-Dec-2015

219 views

Category:

Documents


2 download

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