Click here to Skip to main content
15,891,136 members
Articles / Programming Languages / MSIL

RunSharp - Reflection.Emit Has Never Been Easier

Rate me:
Please Sign up or sign in to vote.
4.92/5 (48 votes)
10 Aug 2009MIT5 min read 118.2K   509   118  
RunSharp (or Run#) is a high-level wrapper around the Reflection.Emit API, allowing you to generate code at runtime quickly and easily.
/*
 * Copyright (c) 2009, Stefan Simek
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;

namespace TriAxis.RunSharp
{
	using Operands;

	interface IMemberInfo
	{
		MemberInfo Member { get; }
		string Name { get; }
		Type ReturnType { get; }
		Type[] ParameterTypes { get; }
		bool IsParameterArray { get; }
		bool IsStatic { get; }
		bool IsOverride { get; }
	}

	interface ITypeInfoProvider
	{
		IEnumerable<IMemberInfo> GetConstructors();
		IEnumerable<IMemberInfo> GetFields();
		IEnumerable<IMemberInfo> GetProperties();
		IEnumerable<IMemberInfo> GetEvents();
		IEnumerable<IMemberInfo> GetMethods();
		string DefaultMember { get; }
	}

	static class TypeInfo
	{
		static Dictionary<Type, ITypeInfoProvider> providers = new Dictionary<Type, ITypeInfoProvider>();
		static Dictionary<Type, WeakReference> cache = new Dictionary<Type, WeakReference>();

		class CacheEntry
		{
			Type t;
			IMemberInfo[] constructors, fields, properties, events, methods;
			static string nullStr = "$NULL";
			string defaultMember = nullStr;

			public CacheEntry(Type t)
			{
				this.t = t;

				if (t.GetType() != typeof(object).GetType())
				{
					// not a runtime type, TypeInfoProvider missing - return nothing
					constructors = fields = properties = events = methods = empty;
					defaultMember = null;
				}
			}

			~CacheEntry()
			{
				lock (cache)
				{
					if (cache[t].Target == this || cache[t].Target == null)
						cache.Remove(t);
				}
			}

			static IMemberInfo[] empty = { };

			public IMemberInfo[] Constructors
			{
				get
				{
					if (constructors == null)
					{
						ConstructorInfo[] ctors = t.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance);
						constructors = Array.ConvertAll<ConstructorInfo, IMemberInfo>(ctors, delegate(ConstructorInfo ci) { return new StdMethodInfo(ci); });
					}
					return constructors;
				}
			}

			public IMemberInfo[] Fields
			{
				get
				{
					if (fields == null)
					{
						FieldInfo[] fis = t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static);
						fields = Array.ConvertAll<FieldInfo, IMemberInfo>(fis, delegate(FieldInfo fi) { return new StdFieldInfo(fi); });
					}
					return fields;
				}
			}

			public IMemberInfo[] Properties
			{
				get
				{
					if (properties == null)
					{
						PropertyInfo[] pis = t.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static);
						properties = Array.ConvertAll<PropertyInfo, IMemberInfo>(pis, delegate(PropertyInfo pi) { return new StdPropertyInfo(pi); });
					}
					return properties;
				}
			}

			public IMemberInfo[] Events
			{
				get
				{
					if (events == null)
					{
						EventInfo[] eis = t.GetEvents(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static);
						events = Array.ConvertAll<EventInfo, IMemberInfo>(eis, delegate(EventInfo ei) { return new StdEventInfo(ei); });
					}
					return events;
				}
			}

			public IMemberInfo[] Methods
			{
				get
				{
					if (methods == null)
					{
						MethodInfo[] mis = t.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static);
						methods = Array.ConvertAll<MethodInfo, IMemberInfo>(mis, delegate(MethodInfo mi) { return new StdMethodInfo(mi); });
					}
					return methods;
				}
			}

			public string DefaultMember
			{
				get
				{
					if (defaultMember == nullStr)
					{
						foreach (DefaultMemberAttribute dma in Attribute.GetCustomAttributes(t, typeof(DefaultMemberAttribute)))
							return defaultMember = dma.MemberName;

						defaultMember = null;
					}
					return defaultMember;
				}
			}
		}

		public static void RegisterProvider(Type t, ITypeInfoProvider prov)
		{
			providers[t] = prov;
		}

		public static void UnregisterProvider(Type t)
		{
			providers.Remove(t);
		}

		static CacheEntry GetCacheEntry(Type t)
		{
			if (t is TypeBuilder)
				t = t.UnderlyingSystemType;

			lock (cache)
			{
				CacheEntry ce;
				WeakReference wr;

				if (cache.TryGetValue(t, out wr))
				{
					ce = wr.Target as CacheEntry;
					if (ce != null)
						return ce;
				}

				ce = new CacheEntry(t);
				cache[t] = new WeakReference(ce);
				return ce;
			}
		}

		public static IEnumerable<IMemberInfo> GetConstructors(Type t)
		{
			ITypeInfoProvider prov;

			if (providers.TryGetValue(t, out prov))
				return prov.GetConstructors();

			return GetCacheEntry(t).Constructors;
		}

		public static IEnumerable<IMemberInfo> GetFields(Type t)
		{
			ITypeInfoProvider prov;

			if (providers.TryGetValue(t, out prov))
				return prov.GetFields();

			return GetCacheEntry(t).Fields;
		}

		public static IEnumerable<IMemberInfo> GetProperties(Type t)
		{
			ITypeInfoProvider prov;

			if (providers.TryGetValue(t, out prov))
				return prov.GetProperties();

			return GetCacheEntry(t).Properties;
		}

		public static IEnumerable<IMemberInfo> GetEvents(Type t)
		{
			ITypeInfoProvider prov;

			if (providers.TryGetValue(t, out prov))
				return prov.GetEvents();

			return GetCacheEntry(t).Events;
		}

		public static IEnumerable<IMemberInfo> GetMethods(Type t)
		{
			ITypeInfoProvider prov;

			if (providers.TryGetValue(t, out prov))
				return prov.GetMethods();

			return GetCacheEntry(t).Methods;
		}

		public static string GetDefaultMember(Type t)
		{
			ITypeInfoProvider prov;

			if (providers.TryGetValue(t, out prov))
				return prov.DefaultMember;

			return GetCacheEntry(t).DefaultMember;
		}

		public static IEnumerable<IMemberInfo> Filter(IEnumerable<IMemberInfo> source, string name, bool ignoreCase, bool isStatic, bool allowOverrides)
		{
			foreach (IMemberInfo mi in source)
			{
				if (mi.IsStatic != isStatic)
					continue;

				if (!allowOverrides && mi.IsOverride)
					continue;

				if (name != null)
				{
					if (ignoreCase)
					{
						if (!mi.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
							continue;
					}
					else
					{
						if (mi.Name != name)
							continue;
					}
				}

				yield return mi;
			}
		}

		public static ApplicableFunction FindConstructor(Type t, Operand[] args)
		{
			ApplicableFunction ctor = OverloadResolver.Resolve(GetConstructors(t), args);

			if (ctor == null)
				throw new MissingMemberException(Properties.Messages.ErrMissingConstructor);

			return ctor;
		}

		public static IMemberInfo FindField(Type t, string name, bool @static)
		{
			for (; t != null; t = t.BaseType)
			{
				foreach (IMemberInfo mi in GetFields(t))
				{
					if (mi.Name == name && mi.IsStatic == @static)
						return mi;
				}
			}

			throw new MissingFieldException(Properties.Messages.ErrMissingField);
		}

		public static ApplicableFunction FindProperty(Type t, string name, Operand[] indexes, bool @static)
		{
			if (name == null)
				name = GetDefaultMember(t);

			for (; t != null; t = t.BaseType)
			{
				ApplicableFunction af = OverloadResolver.Resolve(Filter(GetProperties(t), name, false, @static, false), indexes);

				if (af != null)
					return af;
			}

			throw new MissingMemberException(Properties.Messages.ErrMissingProperty);
		}

		public static IMemberInfo FindEvent(Type t, string name, bool @static)
		{
			for (; t != null; t = t.BaseType)
			{
				foreach (IMemberInfo mi in GetEvents(t))
				{
					if (mi.Name == name && mi.IsStatic == @static)
						return mi;
				}
			}

			throw new MissingMemberException(Properties.Messages.ErrMissingEvent);
		}

		public static ApplicableFunction FindMethod(Type t, string name, Operand[] args, bool @static)
		{
			for (; t != null; t = t.BaseType)
			{
				ApplicableFunction af = OverloadResolver.Resolve(Filter(GetMethods(t), name, false, @static, false), args);

				if (af != null)
					return af;
			}

			throw new MissingMethodException(Properties.Messages.ErrMissingMethod);
		}

		class StdMethodInfo : IMemberInfo
		{
			MethodBase mb;
			MethodInfo mi;
			string name;
			Type returnType;
			Type[] parameterTypes;
			bool hasVar;

			public StdMethodInfo(MethodInfo mi)
				: this((MethodBase)mi)
			{
				this.mi = mi;
			}

			public StdMethodInfo(ConstructorInfo ci)
				: this((MethodBase)ci)
			{
				this.returnType = typeof(void);
			}

			public StdMethodInfo(MethodBase mb)
			{
				this.mb = mb;
			}

			void RequireParameters()
			{
				if (parameterTypes == null)
				{
					ParameterInfo[] pis = mb.GetParameters();
					parameterTypes = ArrayUtils.GetTypes(pis);

					hasVar = pis.Length > 0 &&
						pis[pis.Length - 1].GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0;
				}
			}

			public MemberInfo Member { get { return mb; } }
			public string Name
			{
				get
				{
					if (name == null)
						name = mb.Name;
					return name;
				}
			}
			public Type ReturnType
			{
				get
				{
					if (returnType == null)
						returnType = mi.ReturnType;
					return returnType;
				}
			}
			public Type[] ParameterTypes
			{
				get
				{
					RequireParameters();
					return parameterTypes;
				}
			}
			public bool IsParameterArray
			{
				get
				{
					RequireParameters();
					return hasVar;
				}
			}
			public bool IsStatic { get { return mb.IsStatic; } }
			public bool IsOverride { get { return Utils.IsOverride(mb.Attributes); } }

			public override string ToString()
			{
				return mb.ToString();
			}
		}

		class StdPropertyInfo : IMemberInfo
		{
			PropertyInfo pi;
			string name;
			MethodInfo mi;
			Type returnType;
			Type[] parameterTypes;
			bool hasVar;

			public StdPropertyInfo(PropertyInfo pi)
			{
				this.pi = pi;
				this.mi = pi.GetGetMethod();
				if (mi == null)
					mi = pi.GetSetMethod();
				// mi will remain null for abstract properties
			}

			void RequireParameters()
			{
				if (parameterTypes == null)
				{
					ParameterInfo[] pis = pi.GetIndexParameters();
					parameterTypes = ArrayUtils.GetTypes(pis);

					hasVar = pis.Length > 0 &&
						pis[pis.Length - 1].GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0;
				}
			}

			public MemberInfo Member { get { return pi; } }
			public string Name
			{
				get
				{
					if (name == null)
						name = pi.Name;
					return name;
				}
			}
			public Type ReturnType
			{
				get
				{
					if (returnType == null)
						returnType = pi.PropertyType;
					return returnType;
				}
			}
			public Type[] ParameterTypes
			{
				get
				{
					RequireParameters();
					return parameterTypes;
				}
			}
			public bool IsParameterArray
			{
				get
				{
					RequireParameters();
					return hasVar;
				}
			}
			public bool IsOverride { get { return mi == null ? false : Utils.IsOverride(mi.Attributes); } }
			public bool IsStatic { get { return mi == null ? false : mi.IsStatic; } }

			public override string ToString()
			{
				return pi.ToString();
			}
		}

		class StdEventInfo : IMemberInfo
		{
			EventInfo ei;
			string name;
			MethodInfo mi;

			public StdEventInfo(EventInfo ei)
			{
				this.ei = ei;
				this.name = ei.Name;

				this.mi = ei.GetAddMethod();
				if (mi == null)
					mi = ei.GetRemoveMethod();
				// mi will remain null for abstract properties
			}

			public MemberInfo Member { get { return ei; } }
			public string Name { get { return name; } }
			public Type ReturnType { get { return ei.EventHandlerType; } }
			public Type[] ParameterTypes { get { return Type.EmptyTypes; } }
			public bool IsParameterArray { get { return false; } }
			public bool IsOverride { get { return mi == null ? false : Utils.IsOverride(mi.Attributes); } }
			public bool IsStatic { get { return mi == null ? false : mi.IsStatic; } }

			public override string ToString()
			{
				return ei.ToString();
			}
		}
		
		class StdFieldInfo : IMemberInfo
		{
			FieldInfo fi;
			string name;

			public StdFieldInfo(FieldInfo fi)
			{
				this.fi = fi;
				this.name = fi.Name;
			}

			public MemberInfo Member { get { return fi; } }
			public string Name { get { return name; } }
			public Type ReturnType { get { return fi.FieldType; } }
			public Type[] ParameterTypes { get { return Type.EmptyTypes; } }
			public bool IsParameterArray { get { return false; } }
			public bool IsOverride { get { return false; } }
			public bool IsStatic { get { return fi.IsStatic; } }

			public override string ToString()
			{
				return fi.ToString();
			}
		}
	}

	/*		public Operand Invoke(string name, params Operand[] args)
			{
				Operand target = Target;

				for (Type src = this; src != null; src = src.Base)
				{
					ApplicableFunction match = OverloadResolver.Resolve(Type.FilterMethods(src.GetMethods(), name, false, (object)target == null, false), args);

					if (match != null)
						return new Invocation(match, Target, args);
				}

				throw new MissingMethodException(Properties.Messages.ErrMissingMethod);
			}*/
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Web Developer
Slovakia Slovakia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions