简体   繁体   中英

Can I use System.Reflection.Emit to build a constructor for an existing type?

Does c# have support for building a constructor using a DynamicMethod ? Consider this class:

public class Foo
{
    public string Bar { get; set; }

    public Foo(string bar)
    {
        Bar = bar;
    }
}

I would like to create a new constructor for Foo that takes no arguments, and compile it as a Func<Foo> . For example:

DynamicMethod dyn = new DynamicMethod("NewInitializer", typeof(Foo), Type.EmptyTypes);
ILGenerator il = dyn.GetILGenerator();

LocalBuilder loc0 = il.DeclareLocal(typeof(Foo));
il.Emit(OpCodes.Ldloca_S, loc0);
il.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ret);

Func<Foo> newInitFunc = (Func<Foo>)dyn.CreateDelegate(typeof(Func<Foo>));
Foo f = newInitFunc();

Note, this is just one of the implementations I have tried. Everything ends up throwing an AccessViolationException :

Operation Could Destabilize the Runtime

when I call the method. Is it even possible to create a constructor using a DynamicMethod ?

If inheriting from those types is possible, you could create a class using Emit that inherits from the the existing type and doesn't call the base constructor.

var typeToLoad = typeof(Foo);
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Dynamic"), AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("Dynamic");
var typeBuilder = moduleBuilder.DefineType(typeToLoad.Name, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AnsiClass | TypeAttributes.AutoClass, typeToLoad);
// create a constructor that doesn't call the base constructor
var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName, CallingConventions.Standard, Type.EmptyTypes);
var ilGenerator = constructorBuilder.GetILGenerator();
ilGenerator.Emit(OpCodes.Ret);
// create a factory method so we could create a delegate for it
var methodBuilder = typeBuilder.DefineMethod("Create", MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig, typeBuilder, Type.EmptyTypes);
ilGenerator = methodBuilder.GetILGenerator();
ilGenerator.Emit(OpCodes.Newobj, constructorBuilder);
ilGenerator.Emit(OpCodes.Ret);
var generatedType = typeBuilder.CreateType();
var factory = (Func<Foo>)generatedType.GetMethod("Create", BindingFlags.Public | BindingFlags.Static).CreateDelegate(typeof(Func<Foo>));

This runs as fast as the new operator.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM