CHARLES UNIVERSITY IN PRAGUE faculty of mathematics and physics Advanced.NET Programming I 7 th Lecture Pavel Ježek Some of the slides are based on University of Linz.NET presentations. © University of Linz, Institute for System Software, 2004 published under the Microsoft Curriculum License (
Reflection Class Hierarchy Assembly FieldInfo MethodInfo ConstructorInfo PropertyInfo EventInfo GetConstructors() GetEvents() GetProperties() GetMethods() GetFields() * * * * * MethodBase MemberInfo GetTypes() Type * BaseType * Interfaces
Class Assembly Class Assembly loads assemblies and their meta-data Provides access to its meta-data Loading an assembly Name, storage location, entry point of the assembly Getting modules and all in the assembly defined types Getting type with name typeName Creation of an object of type typeName public class Assembly { public static Assembly Load(string name); public virtual string FullName {get;} public virtual string Location {get;} public virtual MethodInfo EntryPoint {get;} public Module[] GetModules(); public virtual Type[] GetTypes(); public virtual Type GetType(string typeName); public object CreateInstance(string typeName);... }
Class Type Type used for meta-description of all types in the run-time system Provides access to the meta-information about its members public abstract class Type : MemberInfo, IReflect { public abstract string FullName {get;}; public abstract Type BaseType {get;}; public Type[] GetInterfaces(); public bool IsAbstract {get;}; public bool IsClass {get;}; public bool IsPublic {get;}; … public ConstructorInfo[] GetConstructors(); public virtual EventInfo[] GetEvents(); public FieldInfo[] GetFields(); public MethodInfo[] GetMethods(); public PropertyInfo[] GetProperties();... Type name Direct base type List of implemented interfaces Properties of type Getting constructors, events, fields, methods, properties Optionally parameterized by BindingFlags
Example: Handling plug-ins “Plug-in” is any class implementing IMyPlugin interface string[] files = Directory.GetFiles(path, "*.dll");// returns full paths foreach (string f in files) { Assembly a = Assembly.LoadFile(f); Type[] types = a.GetTypes(); foreach (Type t in types) { if (t.IsClass) { if (t.GetInterface(“IMyPlugin”) != null) { IMyPlugin p = (IMyPlugin) Activator.CreateInstance(t); // add p to list of all installed plug-ins }
Attributes with Parameters Example [Obsolete("Use class C1 instead", IsError=true)]// causes compiler message saying public class C {...}// that C is obsolete Positional parameter = parameter of the attribute's constructor Name parameter = a property of the attribute positional parameter name parameters come after pos. parameters values must be constants Valid variants: [Obsolete]// Message == "", IsError == false [Obsolete("some Message")]// IsError == false [Obsolete("some Message", false)] [Obsolete("some Message", IsError=false)] Attributes are declared as classes public class ObsoleteAttribute : Attribute {// class name ends with "Attribute" public string Message { get; }// but can be used as "Obsolete" public bool IsError { get; set; } public ObsoleteAttribute() {...} public ObsoleteAttribute(string msg) {...} public ObsoleteAttribute(string msg, bool error) {...} }
AttributeUsage AttributeUsage describes how user-defined attributes are to be used public class AttributeUsageAttribute : Attribute { public AttributeUsageAttribute (AttributeTargets validOn) {...} public bool AllowMultiple { get; set; }// default: false public bool Inherited { get; set; }// default: false } Usage [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple=false)] public class MyAttribute : Attribute {... }
Defining Your Own Attributes Declaration [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, Inherited=true)] class CommentAttribute : Attribute { string text, author; public string Text { get {return text;} } public string Author { get {return author;} set {author = value;} } public Comment (string text) { this.text = text; author ="HM"; } } Querying the attribute at runtime class Attributes { static void Main() { Type t = typeof(C); object[] a = t.GetCustomAttributes(typeof(Comment Attribute ), true); foreach (CommentAttribute ca in a) { Console.WriteLine(ca.Text + ", " + ca.Author); } Usage [Comment("This is a demo class for Attributes", Author="XX")] class C {... }
Reflection Example Print all existing types in a given assembly Type[] types = a.GetTypes(); foreach (Type t in types) Console.WriteLine(t.FullName); Print all existing methods of a given type Type hw = a.GetType("Hello.HelloWorld"); MethodInfo[] methods = hw.GetMethods(); foreach (MethodInfo m in methods) Console.WriteLine(m.Name); Hello.HelloWorld GetType ToString Equals GetHashCode
Reflection Example Create a new instance of a given type Assembly a = Assembly.Load("HelloWorld"); object o = a.CreateInstance("Hello.HelloWorld"); Get method ToString(), which has no parameters Invoke the method Type hw = a.GetType("Hello.HelloWorld"); MethodInfo mi = hw.GetMethod("ToString"); object retVal = mi.Invoke(o, null);
Reflection: Accessing Private Fields using System.Reflection; class HelperClass { private int privateData; public int PublicData { get { return privateData; } set { privateData = value; } } class Program { static void Main(string[] args) { HelperClass hc = new HelperClass(); hc.PublicData = 123; Type type = hc.GetType(); FieldInfo fi = type.GetField("privateData", BindingFlags.Instance | BindingFlags.NonPublic); Console.WriteLine(fi.GetValue(hc)); fi.SetValue(hc, 456); Console.WriteLine(hc.PublicData); }
Reflection: Accessing Private Fields using System.Reflection; class HelperClass { private int privateData; public int PublicData { get { return privateData; } set { privateData = value; } } class Program { static void Main(string[] args) { HelperClass hc = new HelperClass(); hc.PublicData = 123; Type type = hc.GetType(); FieldInfo fi = type.GetField("privateData", BindingFlags.Instance | BindingFlags.NonPublic); Console.WriteLine(fi.GetValue(hc)); fi.SetValue(hc, 456); Console.WriteLine(hc.PublicData); } WARNING: SLOW & DANGEROUS!!!
MEF
Lambda Expressions as Delegates When assigned to a delegate, equivalent code of an anonymous method is generated at compile time! IL_0000: ldarg.0 IL_0001: ldc.i4.2 IL_0002: add IL_0003: ldc.i4.s 10 IL_0005: mul IL_0006: stloc.0 IL_0007: br.s IL_0009 IL_0009: ldloc.0 IL_000a: ret Func f = value => (value + 2) * 10 Compile time generation
Lambda Expressions as Expression Trees Permit lambda expressions to be represented as data structures instead of executable code Lambda expression convertible to delegate D (assignment causes code generation) is also convertible to expression tree (abstract syntax tree) of type System.Linq.Expressions.Expression (assignment causes expression tree generation – compile time generation of code, that creates the expression tree [class instances] at runtime) Expression trees are immutable IL_0000: ldarg.0 IL_0001: ldc.i4.2 IL_0002: add IL_0003: ldc.i4.s 10 IL_0005: mul IL_0006: stloc.0 IL_0007: br.s IL_0009 IL_0009: ldloc.0 IL_000a: ret new LambdaExpression( new BinaryExpression( ParameterExpression(“value”) ConstantExpression(2) ) ConstantExpression(10) ) Func f = Expression > e = value => (value + 2) * 10 Compile time generation
Expression Trees Classes inheriting from Expression (since.NET 3.5): System.Linq.Expressions.BinaryExpression System.Linq.Expressions.ConditionalExpression System.Linq.Expressions.ConstantExpression System.Linq.Expressions.InvocationExpression System.Linq.Expressions.LambdaExpression System.Linq.Expressions.MemberExpression System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.NewExpression System.Linq.Expressions.NewArrayExpression System.Linq.Expressions.MemberInitExpression System.Linq.Expressions.ListInitExpression System.Linq.Expressions.ParameterExpression System.Linq.Expressions.TypeBinaryExpression System.Linq.Expressions.UnaryExpression New classes inheriting from Expression (since.NET 4.0): System.Linq.Expressions.BlockExpression System.Linq.Expressions.LoopExpression System.Linq.Expressions.TryExpression …
Expression Trees and LINQ
Lambda Expressions as Expression Trees IL_0000: ldarg.0 IL_0001: ldc.i4.2 IL_0002: add IL_0003: ldc.i4.s 10 IL_0005: mul IL_0006: stloc.0 IL_0007: br.s IL_0009 IL_0009: ldloc.0 IL_000a: ret new LambdaExpression( new BinaryExpression( ParameterExpression(“value”) ConstantExpression(2) ) ConstantExpression(10) ) Func f = Expression > e = value => (value + 2) * 10 Compile time generation machine code (e.g. x86) (code actually executed by real CPU) Runtime time generation by JIT
Expression Trees to Dynamic Methods (via Implicit Reflection.Emit) Runtime generation of CIL code of a dynamic method from expression tree instance: IL_0000: ldarg.0 IL_0001: ldc.i4.2 IL_0002: add IL_0003: ldc.i4.s 10 IL_0005: mul IL_0006: stloc.0 IL_0007: br.s IL_0009 IL_0009: ldloc.0 IL_000a: ret new LambdaExpression( new BinaryExpression( ParameterExpression(“value”) ConstantExpression(2) ) ConstantExpression(10) ) Func f = Expression > e = value => (value + 2) * 10 f = e.Compile(); Compile time generation Runtime time generation machine code (e.g. x86) (code actually executed by real CPU) Runtime time generation by JIT