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; } } }
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] "Joe McMenimen" wrote: > 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; > } > } > } >
[quoted text, click to view] Joe McMenimen wrote: > 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);
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#.
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] "Ben Voigt [C++ MVP]" wrote: > Joe McMenimen wrote: > > 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); > > 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#. > >
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] "Joe McMenimen" wrote: > Ben, that is exactly what I did. The suggestion of posting the IL is a great > idea. > > Thanks again. > > Joe > > "Ben Voigt [C++ MVP]" wrote: > > > Joe McMenimen wrote: > > > 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); > > > > 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#. > > > >
Don't see what you're looking for? Try a search.
|