using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection.Emit;
using System.Reflection;
namespace Scaredfingers.Adapters
{
public interface IInjection
{
MethodInfo InjectionSource { get; set; }
Type ResolutionContext { get; set; }
IList<Assembly> References { get; }
void Inject(ILGenerator generator, MethodBuilder method, TypeBuilder container);
}
public abstract class Injection : IInjection
{
#region IInjection Members
protected MethodInfo mth_InjectionSource;
public MethodInfo InjectionSource
{
get
{
return mth_InjectionSource;
}
set
{
mth_InjectionSource = value;
}
}
protected Type typ_ResolutionContext;
public Type ResolutionContext
{
get
{
return typ_ResolutionContext;
}
set
{
typ_ResolutionContext = value ;
}
}
protected IList<Assembly> lst_References = new List<Assembly>();
public IList<Assembly> References
{
get { return lst_References; }
}
public abstract void Inject(ILGenerator generator, MethodBuilder method, TypeBuilder container) ;
#endregion
}
public interface IInjectionAttribute
{
IInjection Injection { get; }
}
public interface IPreInjectionAttribute
{
IInjection Injection { get; }
}
public interface IPostInjectionAttribute
{
IInjection Injection { get; }
}
public class InjectionsAdapterBuilder : AdapterBuilder
{
#region Creation
public InjectionsAdapterBuilder(string assemblyName)
: base(assemblyName)
{
}
public InjectionsAdapterBuilder()
{
}
#endregion
#region Overrides
protected override void EmitMethodBody(ILGenerator generator, FieldBuilder adapteesReferenceField, MethodBuilder methodBuilder,
MethodInfo adapteesMethod, MethodInfo prototypeMethod, Type adapterInterfaceType, Type adapteeType, TypeBuilder adapterTypeBuilder)
{
foreach (IInjection injection in GetPreInjections(adapteesReferenceField, methodBuilder, adapteesMethod, prototypeMethod,
adapterInterfaceType, adapteeType, adapterTypeBuilder))
injection.Inject(generator, methodBuilder, adapterTypeBuilder);
EmitMethodUninjectedMethodBody(generator, adapteesReferenceField, methodBuilder, adapteesMethod, prototypeMethod,
adapterInterfaceType, adapteeType, adapterTypeBuilder);
foreach (IInjection injection in GetPostInjections(adapteesReferenceField, methodBuilder, adapteesMethod, prototypeMethod,
adapterInterfaceType, adapteeType, adapterTypeBuilder))
injection.Inject(generator, methodBuilder, adapterTypeBuilder);
}
protected virtual void EmitMethodUninjectedMethodBody(ILGenerator generator, FieldBuilder adapteesReferenceField, MethodBuilder methodBuilder,
MethodInfo adapteesMethod, MethodInfo prototypeMethod, Type adapterInterfaceType, Type adapteeType, TypeBuilder adapterTypeBuilder)
{
base.EmitMethodBody(generator, adapteesReferenceField, methodBuilder, adapteesMethod, prototypeMethod,
adapterInterfaceType, adapteeType, adapterTypeBuilder);
}
#endregion
#region Virtuals
protected virtual IList<IInjection> GetPreInjections(FieldBuilder adapteesReferenceField, MethodBuilder methodBuilder,
MethodInfo adapteesMethod, MethodInfo prototypeMethod, Type adapterInterfaceType, Type adapteeType, TypeBuilder adapterTypeBuilder)
{
return GetInjections(typeof(IPreInjectionAttribute), adapteesReferenceField, methodBuilder,
adapteesMethod, prototypeMethod, adapterInterfaceType, adapteeType, adapterTypeBuilder);
}
protected virtual IList<IInjection> GetPostInjections(FieldBuilder adapteesReferenceField, MethodBuilder methodBuilder,
MethodInfo adapteesMethod, MethodInfo prototypeMethod, Type adapterInterfaceType, Type adapteeType, TypeBuilder adapterTypeBuilder)
{
return GetInjections(typeof(IPostInjectionAttribute), adapteesReferenceField, methodBuilder,
adapteesMethod, prototypeMethod, adapterInterfaceType, adapteeType, adapterTypeBuilder);
}
protected static readonly AdapterBuilder bdr_Injections = new AdapterBuilder();
protected virtual IList<IInjection> GetInjections(Type injectionsAttributeType, FieldBuilder adapteesReferenceField, MethodBuilder methodBuilder,
MethodInfo adapteesMethod, MethodInfo prototypeMethod, Type adapterInterfaceType, Type adapteeType, TypeBuilder adapterTypeBuilder)
{
List<IInjection> lst_Result = new List<IInjection>();
foreach (object att_Injection in prototypeMethod.GetCustomAttributes(injectionsAttributeType, true))
{
IInjection inj_Injection = ((IInjectionAttribute)bdr_Injections.BindAdapter(typeof(IInjectionAttribute), injectionsAttributeType,
att_Injection)).Injection;
inj_Injection.InjectionSource = prototypeMethod;
inj_Injection.ResolutionContext = adapterInterfaceType;
lst_Result.Add(inj_Injection);
}
foreach (object att_Injection in adapterInterfaceType.GetCustomAttributes(injectionsAttributeType, true))
{
IInjection inj_Injection = ((IInjectionAttribute)bdr_Injections.BindAdapter(typeof(IInjectionAttribute), injectionsAttributeType,
att_Injection)).Injection;
inj_Injection.InjectionSource = prototypeMethod;
inj_Injection.ResolutionContext = adapterInterfaceType;
lst_Result.Add(inj_Injection);
}
return lst_Result;
}
#endregion
}
public abstract class InjectionAttribute : Attribute, IInjectionAttribute
{
#region IInjectionAttribute Members
public abstract IInjection Injection
{
get;
}
#endregion
}
public class LogAttribute : Attribute, IPreInjectionAttribute, IPostInjectionAttribute
{
#region IInjectionAttribute Members
IInjection IPreInjectionAttribute.Injection
{
get { return new LogEnter(); }
}
#endregion
#region IPostInjectionAttribute Members
IInjection IPostInjectionAttribute.Injection
{
get { return new LogExit() ; }
}
#endregion
#region Nested Injections
public abstract class LogInjection : Injection
{
protected string SignatureToString(MethodInfo method)
{
return string.Format("{0} {1}::{2}({3})", method.ReturnType.FullName, method.ReflectedType.FullName,
method.Name, ParametersToString(method.GetParameters()));
}
protected string ParametersToString(ParameterInfo[] formalParameters)
{
string result = "";
foreach (ParameterInfo param in formalParameters)
result += "," + param.ParameterType.FullName;
return result.Length > 0? result.Substring(1) : "";
}
}
public class LogEnter : LogInjection
{
public override void Inject(ILGenerator generator, MethodBuilder method, TypeBuilder container)
{
generator.EmitWriteLine("[Enter]" + SignatureToString(InjectionSource));
}
}
public class LogExit : LogInjection
{
public override void Inject(ILGenerator generator, MethodBuilder method, TypeBuilder container)
{
generator.EmitWriteLine("[Exit]" + SignatureToString(InjectionSource));
}
}
#endregion
}
}