public static class ProxyGenerator
{
public static T GetProxy<T>(object instance) where T : class
{
AssemblyBuilder asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
new AssemblyName
("TMP"), AssemblyBuilderAccess.
Run);
ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule("TMP");
TypeBuilder typeBuilder = modBuilder.DefineType(ifaceType.Name + "_Impl", TypeAttributes.Public);
typeBuilder.AddInterfaceImplementation(ifaceType);
FieldBuilder instanceField = typeBuilder.
DefineField("instance",
typeof(Object), FieldAttributes.
Private);
FieldBuilder instanceTypeField = typeBuilder.
DefineField("instanceType",
typeof(Type
), FieldAttributes.
Private);
ConstructorBuilder conBuilder = typeBuilder.DefineConstructor(
MethodAttributes.
Public, CallingConventions.
Standard,
new Type
[] { typeof(Object),
typeof(Type
) });
ILGenerator cgen = conBuilder.GetILGenerator();
cgen.Emit(OpCodes.Ldarg, 0);
cgen.
Emit(OpCodes.
Call,
typeof(Object).
GetConstructor(new Type
[0]));
cgen.Emit(OpCodes.Ldarg, 0);
cgen.Emit(OpCodes.Ldarg, 1);
cgen.Emit(OpCodes.Stfld, instanceField);
cgen.Emit(OpCodes.Ldarg, 0);
cgen.Emit(OpCodes.Ldarg, 2);
cgen.Emit(OpCodes.Stfld, instanceTypeField);
cgen.Emit(OpCodes.Ret);
foreach (MethodInfo mi in ifaceType.GetMethods())
{
if (!mi.Name.StartsWith("get_") && !mi.Name.StartsWith("set_"))
GenerateMethod(typeBuilder, mi, instanceField, instanceTypeField, false);
}
foreach (PropertyInfo pi in ifaceType.GetProperties())
{
PropertyBuilder propBuilder = typeBuilder.DefineProperty(pi.Name, pi.Attributes,
pi.PropertyType, null);
if (pi.CanRead)
{
MethodInfo mi = ifaceType.GetMethod("get_" + pi.Name);
propBuilder.SetGetMethod(GenerateMethod(typeBuilder, mi, instanceField, instanceTypeField, true));
}
if (pi.CanWrite)
{
MethodInfo mi = ifaceType.GetMethod("set_" + pi.Name);
propBuilder.SetSetMethod(GenerateMethod(typeBuilder, mi, instanceField, instanceTypeField, true));
}
}
Type type = typeBuilder.CreateType();
return Activator.
CreateInstance(type,
new object[] { instance, instance.
GetType() }) as T;
}
private static MethodBuilder GenerateMethod(TypeBuilder typeBuilder, MethodInfo mi,
FieldBuilder instanceField, FieldBuilder instanceTypeField, bool specialName)
{
ParameterInfo[] pars = mi.GetParameters();
Type
[] parTypes = pars.
Length >
0 ?
new Type
[pars.
Length] :
null;
for (int i = 0; i < pars.Length; i++)
parTypes[i] = pars[i].ParameterType;
MethodAttributes ma = MethodAttributes.Public | MethodAttributes.Virtual |
( specialName ? MethodAttributes.HideBySig | MethodAttributes.SpecialName : MethodAttributes.HideBySig);
MethodBuilder methBuilder = typeBuilder.DefineMethod(mi.Name, ma,
mi.
ReturnType !=
typeof(void) ? mi.
ReturnType :
null, parTypes
);
for (int i = 0; i < pars.Length; i++)
methBuilder.DefineParameter(i + 1, pars[i].Attributes, pars[i].Name);
ILGenerator gen = methBuilder.GetILGenerator();
LocalBuilder loc = gen.
DeclareLocal(typeof(MethodInfo
));
int offset = 0;
if (pars.Length > 0)
{
gen.
DeclareLocal(typeof(object[]));
gen.
DeclareLocal(typeof(object[]));
offset += 2;
}
if (mi.
ReturnType !=
typeof(void)) {
gen.DeclareLocal(methBuilder.ReturnType);
offset++;
}
gen.Emit(OpCodes.Ldarg, 0);
gen.Emit(OpCodes.Ldfld, instanceTypeField);
gen.Emit(OpCodes.Ldstr, methBuilder.Name);
gen.
EmitCall(OpCodes.
Callvirt,
typeof(Type
).
GetMethod("GetMethod",
new Type
[] { typeof(String) }),
new Type
[] { typeof(String) });
gen.Emit(OpCodes.Stloc, 0);
if (pars.Length > 0)
{
gen.Emit(OpCodes.Ldc_I4, pars.Length);
gen.
Emit(OpCodes.
Newarr,
typeof(Object));
gen.Emit(OpCodes.Stloc, 2);
gen.Emit(OpCodes.Ldloc, 2);
for (int i = 0; i < pars.Length; i++)
{
ParameterInfo p = pars[i];
gen.Emit(OpCodes.Ldc_I4, i);
gen.Emit(OpCodes.Ldarg, i + 1);
if (p.ParameterType.IsValueType)
gen.Emit(OpCodes.Box, p.ParameterType);
gen.Emit(OpCodes.Stelem_Ref);
gen.Emit(OpCodes.Ldloc, 2);
}
gen.Emit(OpCodes.Stloc, 1);
gen.Emit(OpCodes.Ldloc, 0);
gen.Emit(OpCodes.Ldarg, 0);
gen.Emit(OpCodes.Ldfld, instanceField);
gen.Emit(OpCodes.Ldloc, 1);
}
else
{
gen.Emit(OpCodes.Ldloc, 0);
gen.Emit(OpCodes.Ldarg, 0);
gen.Emit(OpCodes.Ldfld, instanceField);
gen.Emit(OpCodes.Ldnull);
}
gen.
EmitCall(OpCodes.
Callvirt,
typeof(MethodBase
).
GetMethod("Invoke", methParams
), methParams
);
if (mi.
ReturnType !=
typeof(void)) {
if (methBuilder.ReturnType.IsValueType)
gen.Emit(OpCodes.Unbox_Any, methBuilder.ReturnType);
gen.Emit(OpCodes.Stloc, offset);
gen.Emit(OpCodes.Ldloc, offset);
}
else
gen.Emit(OpCodes.Pop);
gen.Emit(OpCodes.Ret);
return methBuilder;
}
}
// *********************************
// Как использовать
public interface IDuck
{
void Swim();
}
public class SwimmingAnimal
{
public void Swim()
{
Console.WriteLine("Hey, we are swimming!");
}
}
SwimmingAnimal animal =
new SwimmingAnimal
();
IDuck duck = ProxyGenerator.GetProxy<IDuck>(animal);
duck.Swim();