J
jehugaleahsa
Hello:
I want to play around with a class that can generate types dynamically
at runtime. This class will be given an instance of an interface and
automatically implement a dynamic decorator class that implements the
same interface. All the decorator will do is delegate all calls to the
given instance.
The big idea is to give me another level indirection. Below is what I
have written so far. However, it keeps telling me that my properties
and methods aren't implemented. If someone could please fix my
mistakes and perhaps add additional logic for delegating to any other
language constructs, such as events, etc.
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
namespace Lookup
{
/// <summary>
/// Generates decorators for instances of the specified interface.
/// </summary>
/// <typeparam name="TInterface">The interface type.</typeparam>
public class DecoratorFactory<TInterface>
where TInterface : class
{
private static readonly Type _dynamicType;
/// <summary>
/// Creates a dynamic type that implement the generic type
interface.
/// </summary>
static DecoratorFactory()
{
Type type = typeof(TInterface);
if (!type.IsInterface)
{
throw new InvalidOperationException("The type argument
to DecoratorFactory must be an interface.");
}
AssemblyName assemblyName = new AssemblyName
("LookupDecorators");
AssemblyBuilder assemblyBuilder
= AppDomain.CurrentDomain.DefineDynamicAssembly
(assemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder =
assemblyBuilder.DefineDynamicModule(assemblyName.Name);
string typeName = type.Name + "LookupDecorator";
TypeBuilder typeBuilder = moduleBuilder.DefineType
(typeName,
TypeAttributes.Class | TypeAttributes.Public |
TypeAttributes.Sealed,
typeof(Object),
new Type[] { type });
FieldBuilder fieldBuilder = typeBuilder.DefineField
("_instance", type, FieldAttributes.Private);
emitConstructor(type, typeBuilder, fieldBuilder);
emitPropertiesAndMethods(type, typeBuilder, fieldBuilder);
_dynamicType = typeBuilder.CreateType();
}
/// <summary>
/// Creates a constructor that takes an instance of the
interface type and stores it
/// in a backing field.
/// </summary>
/// <param name="type">The interface type.</param>
/// <param name="typeBuilder">The decorator type builder.</
param>
/// <param name="fieldInfo">The backing field builder.</param>
private static void emitConstructor(Type type, TypeBuilder
typeBuilder, FieldInfo fieldInfo)
{
ConstructorBuilder ctorBuilder =
typeBuilder.DefineConstructor(MethodAttributes.Public,
CallingConventions.Standard,
new Type[] { type });
ILGenerator ctorGenerator = ctorBuilder.GetILGenerator();
ctorGenerator.Emit(OpCodes.Ldarg_0);
ctorGenerator.Emit(OpCodes.Call, typeof
(object).GetConstructor(Type.EmptyTypes));
ctorGenerator.Emit(OpCodes.Ldarg_0);
ctorGenerator.Emit(OpCodes.Ldarg_1);
ctorGenerator.Emit(OpCodes.Stfld, fieldInfo);
ctorGenerator.Emit(OpCodes.Ret);
}
/// <summary>
/// Emits properties and methods for the interface type (and
its interfaces)
/// such that they delegate to the underlying field's
properties and methods.
/// </summary>
/// <param name="type">The interface type.</param>
/// <param name="typeBuilder">The decorator type builder.</
param>
/// <param name="fieldInfo">The backing field builder.</param>
private static void emitPropertiesAndMethods(Type type,
TypeBuilder typeBuilder, FieldInfo fieldInfo)
{
emitProperties(type, typeBuilder, fieldInfo);
emitMethods(type, typeBuilder, fieldInfo);
foreach (Type interfaceType in type.GetInterfaces())
{
emitPropertiesAndMethods(interfaceType, typeBuilder,
fieldInfo);
}
}
/// <summary>
/// Emits properties for the interface type such that they
/// delegate to the underlying field.
/// </summary>
/// <param name="type">The interface type.</param>
/// <param name="typeBuilder">The decorator type builder.</
param>
/// <param name="fieldInfo">The backing field builder.</param>
private static void emitProperties(Type type, TypeBuilder
typeBuilder, FieldInfo fieldInfo)
{
foreach (PropertyInfo propertyInfo in type.GetProperties
())
{
emitProperty(type, typeBuilder, fieldInfo,
propertyInfo);
}
}
/// <summary>
/// Emits a property for the interface type such that it
/// delegates to the corresponding property of the underlying
field.
/// </summary>
/// <param name="type">The interface type.</param>
/// <param name="typeBuilder">The decorator type builder.</
param>
/// <param name="fieldInfo">The backing field builder.</param>
/// <param name="propertyInfo">The property being delegated
to.</param>
private static void emitProperty(Type type, TypeBuilder
typeBuilder, FieldInfo fieldInfo, PropertyInfo propertyInfo)
{
PropertyBuilder propertyBuilder =
typeBuilder.DefineProperty(propertyInfo.Name,
propertyInfo.Attributes,
propertyInfo.PropertyType,
null);
if (propertyInfo.CanRead)
{
MethodInfo methodInfo = propertyInfo.GetGetMethod();
MethodBuilder getterBuilder = typeBuilder.DefineMethod
("get_" + propertyInfo.Name,
methodInfo.Attributes,
methodInfo.CallingConvention,
methodInfo.ReturnType,
Type.EmptyTypes);
ILGenerator getterGenerator =
getterBuilder.GetILGenerator();
getterGenerator.Emit(OpCodes.Ldarg_0);
getterGenerator.Emit(OpCodes.Ldfld, fieldInfo);
getterGenerator.Emit(OpCodes.Call, methodInfo);
getterGenerator.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getterBuilder);
}
if (propertyInfo.CanWrite)
{
MethodInfo methodInfo = propertyInfo.GetSetMethod();
MethodBuilder setterBuilder = typeBuilder.DefineMethod
("set_" + propertyInfo.Name,
methodInfo.Attributes,
methodInfo.CallingConvention,
methodInfo.ReturnType,
new Type[] { propertyInfo.PropertyType });
ILGenerator setterGenerator =
setterBuilder.GetILGenerator();
setterGenerator.Emit(OpCodes.Ldarg_0);
setterGenerator.Emit(OpCodes.Ldfld, fieldInfo);
setterGenerator.Emit(OpCodes.Ldarg_1);
setterGenerator.Emit(OpCodes.Call, methodInfo);
setterGenerator.Emit(OpCodes.Ret);
propertyBuilder.SetSetMethod(setterBuilder);
}
}
/// <summary>
/// Emits methods for the interface type such that they
/// delegate to the underlying field.
/// </summary>
/// <param name="type">The interface type.</param>
/// <param name="typeBuilder">The decorated type builder.</
param>
/// <param name="fieldInfo">The backing field builder.</param>
private static void emitMethods(Type type, TypeBuilder
typeBuilder, FieldInfo fieldInfo)
{
foreach (MethodInfo methodInfo in type.GetMethods())
{
if ((methodInfo.Attributes &
MethodAttributes.SpecialName) == 0)
{
emitMethod(type, typeBuilder, fieldInfo,
methodInfo);
}
}
}
/// <summary>
/// Emits a method for the interface type such that it
/// delegates to the corresponding method of the underlying
field.
/// </summary>
/// <param name="type">The interface type.</param>
/// <param name="typeBuilder">The decorator type builder.</
param>
/// <param name="fieldInfo">The backing field builder.</param>
/// <param name="methodInfo">The method being delegated to.</
param>
private static void emitMethod(Type type, TypeBuilder
typeBuilder, FieldInfo fieldInfo, MethodInfo methodInfo)
{
ParameterInfo[] parameters = methodInfo.GetParameters();
List<Type> parameterTypes = new List<Type>();
foreach (ParameterInfo parameterInfo in parameters)
{
parameterTypes.Add(parameterInfo.ParameterType);
}
MethodBuilder methodBuilder = typeBuilder.DefineMethod
(methodInfo.Name,
methodInfo.Attributes,
methodInfo.CallingConvention,
methodInfo.ReturnType,
parameterTypes.ToArray());
ILGenerator bodyGenerator = methodBuilder.GetILGenerator
();
bodyGenerator.Emit(OpCodes.Ldarg_0);
bodyGenerator.Emit(OpCodes.Ldfld, fieldInfo);
for (int parameterIndex = 1; parameterIndex <
parameters.Length; ++parameterIndex)
{
bodyGenerator.Emit(OpCodes.Ldarg, parameterIndex);
}
bodyGenerator.Emit(OpCodes.Call, methodInfo);
bodyGenerator.Emit(OpCodes.Ret);
}
/// <summary>
/// Creates a decorator implementing the interface.
/// </summary>
/// <typeparam name="TInterface">The type of the interface.</
typeparam>
/// <returns>A decorator.</returns>
public TInterface CreateDecorator(TInterface instance)
{
ConstructorInfo constructor = _dynamicType.GetConstructor
(new Type[] { typeof(TInterface) });
return (TInterface)constructor.Invoke(new object[]
{ instance });
}
}
}
I want to play around with a class that can generate types dynamically
at runtime. This class will be given an instance of an interface and
automatically implement a dynamic decorator class that implements the
same interface. All the decorator will do is delegate all calls to the
given instance.
The big idea is to give me another level indirection. Below is what I
have written so far. However, it keeps telling me that my properties
and methods aren't implemented. If someone could please fix my
mistakes and perhaps add additional logic for delegating to any other
language constructs, such as events, etc.
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
namespace Lookup
{
/// <summary>
/// Generates decorators for instances of the specified interface.
/// </summary>
/// <typeparam name="TInterface">The interface type.</typeparam>
public class DecoratorFactory<TInterface>
where TInterface : class
{
private static readonly Type _dynamicType;
/// <summary>
/// Creates a dynamic type that implement the generic type
interface.
/// </summary>
static DecoratorFactory()
{
Type type = typeof(TInterface);
if (!type.IsInterface)
{
throw new InvalidOperationException("The type argument
to DecoratorFactory must be an interface.");
}
AssemblyName assemblyName = new AssemblyName
("LookupDecorators");
AssemblyBuilder assemblyBuilder
= AppDomain.CurrentDomain.DefineDynamicAssembly
(assemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder =
assemblyBuilder.DefineDynamicModule(assemblyName.Name);
string typeName = type.Name + "LookupDecorator";
TypeBuilder typeBuilder = moduleBuilder.DefineType
(typeName,
TypeAttributes.Class | TypeAttributes.Public |
TypeAttributes.Sealed,
typeof(Object),
new Type[] { type });
FieldBuilder fieldBuilder = typeBuilder.DefineField
("_instance", type, FieldAttributes.Private);
emitConstructor(type, typeBuilder, fieldBuilder);
emitPropertiesAndMethods(type, typeBuilder, fieldBuilder);
_dynamicType = typeBuilder.CreateType();
}
/// <summary>
/// Creates a constructor that takes an instance of the
interface type and stores it
/// in a backing field.
/// </summary>
/// <param name="type">The interface type.</param>
/// <param name="typeBuilder">The decorator type builder.</
param>
/// <param name="fieldInfo">The backing field builder.</param>
private static void emitConstructor(Type type, TypeBuilder
typeBuilder, FieldInfo fieldInfo)
{
ConstructorBuilder ctorBuilder =
typeBuilder.DefineConstructor(MethodAttributes.Public,
CallingConventions.Standard,
new Type[] { type });
ILGenerator ctorGenerator = ctorBuilder.GetILGenerator();
ctorGenerator.Emit(OpCodes.Ldarg_0);
ctorGenerator.Emit(OpCodes.Call, typeof
(object).GetConstructor(Type.EmptyTypes));
ctorGenerator.Emit(OpCodes.Ldarg_0);
ctorGenerator.Emit(OpCodes.Ldarg_1);
ctorGenerator.Emit(OpCodes.Stfld, fieldInfo);
ctorGenerator.Emit(OpCodes.Ret);
}
/// <summary>
/// Emits properties and methods for the interface type (and
its interfaces)
/// such that they delegate to the underlying field's
properties and methods.
/// </summary>
/// <param name="type">The interface type.</param>
/// <param name="typeBuilder">The decorator type builder.</
param>
/// <param name="fieldInfo">The backing field builder.</param>
private static void emitPropertiesAndMethods(Type type,
TypeBuilder typeBuilder, FieldInfo fieldInfo)
{
emitProperties(type, typeBuilder, fieldInfo);
emitMethods(type, typeBuilder, fieldInfo);
foreach (Type interfaceType in type.GetInterfaces())
{
emitPropertiesAndMethods(interfaceType, typeBuilder,
fieldInfo);
}
}
/// <summary>
/// Emits properties for the interface type such that they
/// delegate to the underlying field.
/// </summary>
/// <param name="type">The interface type.</param>
/// <param name="typeBuilder">The decorator type builder.</
param>
/// <param name="fieldInfo">The backing field builder.</param>
private static void emitProperties(Type type, TypeBuilder
typeBuilder, FieldInfo fieldInfo)
{
foreach (PropertyInfo propertyInfo in type.GetProperties
())
{
emitProperty(type, typeBuilder, fieldInfo,
propertyInfo);
}
}
/// <summary>
/// Emits a property for the interface type such that it
/// delegates to the corresponding property of the underlying
field.
/// </summary>
/// <param name="type">The interface type.</param>
/// <param name="typeBuilder">The decorator type builder.</
param>
/// <param name="fieldInfo">The backing field builder.</param>
/// <param name="propertyInfo">The property being delegated
to.</param>
private static void emitProperty(Type type, TypeBuilder
typeBuilder, FieldInfo fieldInfo, PropertyInfo propertyInfo)
{
PropertyBuilder propertyBuilder =
typeBuilder.DefineProperty(propertyInfo.Name,
propertyInfo.Attributes,
propertyInfo.PropertyType,
null);
if (propertyInfo.CanRead)
{
MethodInfo methodInfo = propertyInfo.GetGetMethod();
MethodBuilder getterBuilder = typeBuilder.DefineMethod
("get_" + propertyInfo.Name,
methodInfo.Attributes,
methodInfo.CallingConvention,
methodInfo.ReturnType,
Type.EmptyTypes);
ILGenerator getterGenerator =
getterBuilder.GetILGenerator();
getterGenerator.Emit(OpCodes.Ldarg_0);
getterGenerator.Emit(OpCodes.Ldfld, fieldInfo);
getterGenerator.Emit(OpCodes.Call, methodInfo);
getterGenerator.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getterBuilder);
}
if (propertyInfo.CanWrite)
{
MethodInfo methodInfo = propertyInfo.GetSetMethod();
MethodBuilder setterBuilder = typeBuilder.DefineMethod
("set_" + propertyInfo.Name,
methodInfo.Attributes,
methodInfo.CallingConvention,
methodInfo.ReturnType,
new Type[] { propertyInfo.PropertyType });
ILGenerator setterGenerator =
setterBuilder.GetILGenerator();
setterGenerator.Emit(OpCodes.Ldarg_0);
setterGenerator.Emit(OpCodes.Ldfld, fieldInfo);
setterGenerator.Emit(OpCodes.Ldarg_1);
setterGenerator.Emit(OpCodes.Call, methodInfo);
setterGenerator.Emit(OpCodes.Ret);
propertyBuilder.SetSetMethod(setterBuilder);
}
}
/// <summary>
/// Emits methods for the interface type such that they
/// delegate to the underlying field.
/// </summary>
/// <param name="type">The interface type.</param>
/// <param name="typeBuilder">The decorated type builder.</
param>
/// <param name="fieldInfo">The backing field builder.</param>
private static void emitMethods(Type type, TypeBuilder
typeBuilder, FieldInfo fieldInfo)
{
foreach (MethodInfo methodInfo in type.GetMethods())
{
if ((methodInfo.Attributes &
MethodAttributes.SpecialName) == 0)
{
emitMethod(type, typeBuilder, fieldInfo,
methodInfo);
}
}
}
/// <summary>
/// Emits a method for the interface type such that it
/// delegates to the corresponding method of the underlying
field.
/// </summary>
/// <param name="type">The interface type.</param>
/// <param name="typeBuilder">The decorator type builder.</
param>
/// <param name="fieldInfo">The backing field builder.</param>
/// <param name="methodInfo">The method being delegated to.</
param>
private static void emitMethod(Type type, TypeBuilder
typeBuilder, FieldInfo fieldInfo, MethodInfo methodInfo)
{
ParameterInfo[] parameters = methodInfo.GetParameters();
List<Type> parameterTypes = new List<Type>();
foreach (ParameterInfo parameterInfo in parameters)
{
parameterTypes.Add(parameterInfo.ParameterType);
}
MethodBuilder methodBuilder = typeBuilder.DefineMethod
(methodInfo.Name,
methodInfo.Attributes,
methodInfo.CallingConvention,
methodInfo.ReturnType,
parameterTypes.ToArray());
ILGenerator bodyGenerator = methodBuilder.GetILGenerator
();
bodyGenerator.Emit(OpCodes.Ldarg_0);
bodyGenerator.Emit(OpCodes.Ldfld, fieldInfo);
for (int parameterIndex = 1; parameterIndex <
parameters.Length; ++parameterIndex)
{
bodyGenerator.Emit(OpCodes.Ldarg, parameterIndex);
}
bodyGenerator.Emit(OpCodes.Call, methodInfo);
bodyGenerator.Emit(OpCodes.Ret);
}
/// <summary>
/// Creates a decorator implementing the interface.
/// </summary>
/// <typeparam name="TInterface">The type of the interface.</
typeparam>
/// <returns>A decorator.</returns>
public TInterface CreateDecorator(TInterface instance)
{
ConstructorInfo constructor = _dynamicType.GetConstructor
(new Type[] { typeof(TInterface) });
return (TInterface)constructor.Invoke(new object[]
{ instance });
}
}
}