all groups > dotnet clr > march 2008 >
You're in the

dotnet clr

group:

Using Reflection Emit and Creating Instances



Using Reflection Emit and Creating Instances Joe McMenimen
3/26/2008 9:06:02 AM
dotnet clr: I am trying to use the Reflection Emit capability of the framework to
dynamically inherit a base class. I want to call the base classes constructor
with arguments passed into the new classes constructor. I think I am close,
but get the following error trying to activate the new class.


System.Reflection.TargetInvocationException was unhandled
Message="Exception has been thrown by the target of an invocation."
Source="mscorlib"
StackTrace:
at System.RuntimeMethodHandle._InvokeConstructor(Object[] args,
SignatureStruct& signature, IntPtr declaringType)
at System.RuntimeMethodHandle.InvokeConstructor(Object[] args,
SignatureStruct signature, RuntimeTypeHandle declaringType)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags
invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr,
Binder binder, Object[] args, CultureInfo culture, Object[]
activationAttributes)
at System.Activator.CreateInstance(Type type, BindingFlags
bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[]
activationAttributes)
at System.Activator.CreateInstance(Type type, BindingFlags
bindingAttr, Binder binder, Object[] args, CultureInfo culture)
at ReflectionEmit.Program.Main(String[] args) in C:\Documents and
Settings\jmcmeni\Desktop\ReflectionEmit\ReflectionEmit\Program.cs:line 47
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence
assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException: System.InvalidProgramException
Message="Common Language Runtime detected an invalid program."
Source="Test"
StackTrace:
at AmericanCar..ctor(String , String )
InnerException:


Here is the small sample that I'm trying to get to work.

Any help would be great.

thanks

Joe

Program



using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;

namespace ReflectionEmit
{
class Program
{
static void Main(string[] args)
{
AssemblyName assemblyName = new AssemblyName();
assemblyName.Name = "Test";
AssemblyBuilder assemblyBuilder =
Thread.GetDomain().DefineDynamicAssembly(assemblyName,
AssemblyBuilderAccess.RunAndSave);
ModuleBuilder module;
module = assemblyBuilder.DefineDynamicModule("Test.dll");

// create a new type to hold our Main method
TypeBuilder typeBuilder = module.DefineType("AmericanCar",
TypeAttributes.Public | TypeAttributes.Class, typeof(Car));


typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
FieldBuilder fb = typeBuilder.DefineField("brand",
typeof(string), FieldAttributes.Private);

ConstructorInfo ci = typeof(Car).GetConstructor(new Type[] {
typeof(string) });

ConstructorBuilder cb = typeBuilder.DefineConstructor(
ci.Attributes,
ci.CallingConvention, new Type[] { typeof(string),
typeof(string) });

ILGenerator il = cb.GetILGenerator();

int paramCount = ci.GetParameters().Length;
il.Emit(OpCodes.Ldarg_0);
for (int i = 1; i <= paramCount; i++)
{
il.Emit(OpCodes.Ldarg_S, i);
}
il.Emit(OpCodes.Call, ci);

il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_2);
il.Emit(OpCodes.Stfld, fb);

Type type = typeBuilder.CreateType();
assemblyBuilder.Save("Test.dll");

object o = Activator.CreateInstance(type,
BindingFlags.CreateInstance, null, new object[]{"Red","Corvette"},
System.Globalization.CultureInfo.CurrentCulture);

}

}

public class Car
{
private string color;

public string Color
{
get { return color; }
set { color = value; }
}

public Car() { }

public Car(string color)
{
this.color = color;
}
}
}

RE: Using Reflection Emit and Creating Instances Joe McMenimen
3/26/2008 10:38:11 AM
Actually figurred out the issue. After creating the constructor and Emitting
the code to set the field, I forgot to Emit the return from the constructor.

il.Emit(OpCodes.Ret);

Joe

[quoted text, click to view]
Re: Using Reflection Emit and Creating Instances Ben Voigt [C++ MVP]
3/26/2008 5:05:12 PM
[quoted text, click to view]

Best thing to do in these cases is to save the generated assembly (you
already do that, with SaveAndRun), and use Roeder's Reflector to look at the
IL.

Posting the IL is a lot better than the Reflection.Emit code that creates
it.... unless you know what IL you need and can't figure out what
Reflection.Emit calls would produce it.

In fact, sometimes Reflector will tell you what's wrong with the IL,
especially if you change the display language between IL and C#.

Re: Using Reflection Emit and Creating Instances Joe McMenimen
3/27/2008 12:04:07 PM
Ben, that is exactly what I did. The suggestion of posting the IL is a great
idea.

Thanks again.

Joe

[quoted text, click to view]
Re: Using Reflection Emit and Creating Instances john conwell
3/28/2008 8:25:00 AM
I just ran across Reflector addin that might be really useful with writing
Reflection Emit code.

In the Reflector code window it shows the Reflection Emit code needed to
generate the method/class selected on the left panel in Reflector.

http://www.codeplex.com/reflectoraddins/Wiki/View.aspx?title=ReflectionEmitLanguage&referringTitle=Home

I havent actually compared its generated Reflection Emit code to the code
i've written manually to validate its quality, but just playing around with
it, the generated code looks pretty good.


[quoted text, click to view]
AddThis Social Bookmark Button