Skip to content

Instantly share code, notes, and snippets.

@JakobFerdinand
Last active October 3, 2018 05:17
Show Gist options
  • Save JakobFerdinand/79ec750c939cf9e67e40ffce5fcca00e to your computer and use it in GitHub Desktop.
Save JakobFerdinand/79ec750c939cf9e67e40ffce5fcca00e to your computer and use it in GitHub Desktop.
A script to create a dynamic subtype of a given type and overrides all virtual properties. Can be extended to raise events, call logging methods, etc...
using System.Linq;
using System.Reflection.Emit;
using System.Reflection;
using static System.Console;
public T CreateProxy<T>() where T : class
{
var baseType = typeof(T);
var assemblyName = new AssemblyName("Poxies");
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
var moduleBuilder = assemblyBuilder.DefineDynamicModule($"{assemblyName.Name}.dll");
string dynamicTypeName = Assembly.CreateQualifiedName(assemblyName.FullName, $"{baseType.Name}_Proxy");
var typeBuilder = moduleBuilder.DefineType(dynamicTypeName, TypeAttributes.Public | TypeAttributes.Class, baseType);
var getSetAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual;
var propertiesToOverride = baseType.GetProperties()
.Where(p => p.GetGetMethod().IsVirtual)
.ToArray();
foreach (var p in propertiesToOverride)
{
var propertyBuilder = typeBuilder.DefineProperty(p.Name, PropertyAttributes.None, CallingConventions.HasThis, p.PropertyType, Type.EmptyTypes);
var getMethod = typeBuilder.DefineMethod($"get_{p.Name}", getSetAttributes, p.PropertyType, Type.EmptyTypes);
var getIlGenerator = getMethod.GetILGenerator();
getIlGenerator.Emit(OpCodes.Ldarg_0);
getIlGenerator.Emit(OpCodes.Call, p.GetGetMethod());
getIlGenerator.Emit(OpCodes.Ret);
var setMethod = typeBuilder.DefineMethod($"set_{p.Name}", getSetAttributes, null, new[] { p.PropertyType });
var setIlGenerator = setMethod.GetILGenerator();
setIlGenerator.Emit(OpCodes.Ldarg_0);
setIlGenerator.Emit(OpCodes.Ldarg_1);
setIlGenerator.Emit(OpCodes.Call, p.GetSetMethod());
setIlGenerator.Emit(OpCodes.Nop);
setIlGenerator.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getMethod);
propertyBuilder.SetSetMethod(setMethod);
}
var proxyType = typeBuilder.CreateType();
// WriteLine($"AssemblyName: {assemblyName.Name}");
// assemblyBuilder.Save($"{assemblyName.Name}.dll");
return (T)Activator.CreateInstance(proxyType);
}
class BaseType
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
var t = CreateProxy<BaseType>();
t.Id = 5;
t.Name = "Hallo";
WriteLine(t.Id);
WriteLine(t.Name);
var type = t.GetType();
var properties = type
.GetProperties()
.Select(p => (getter: p.GetGetMethod(), setters: p.GetSetMethod()))
.ToArray();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment