4

I am using Reflection.Emit and I want to create a type that would be the equivalent of the following type defined in C#:

class A
{
    public Tuple<A, int> GetValue(int x)
    {
         return new Tuple<A, int>(this, x);
    }
}

The trick is that I need to use a generic type from BCL that uses my custom type as a generic argument.

I'm messing with the following snippet:

var asmName = new AssemblyName("Test");
var access = AssemblyBuilderAccess.Run;
var asm = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, access);
var module = asm.DefineDynamicModule("Test");

var aType = module.DefineType("A");
var tupleType = typeof(Tuple<,>).MakeGenericType(aType, typeof(int));

var attrs = MethodAttributes.Public;
var method = aType.DefineMethod("GetValue", attrs, tupleType, new [] { typeof(int) });
var gen = method.GetILGenerator();

gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);

// here is the fail:
var ctor = tupleType.GetConstructor(new [] { typeof(int), aType } );
gen.Emit(OpCodes.Newobj, ctor);

The call to GetConstructor fails with the following exception:

NotSupportedException: Specified method is not supported.

So, basically, it won't let me get the constructor of a type that merely references my custom type, and neither can I finalize the type before emitting the body of its method.

Can it really be impossible to get out of this vicious circle?

Impworks
  • 2,647
  • 3
  • 25
  • 53
  • What are the exception details? – Peter Ritchie Mar 27 '13 at 21:08
  • I added the information about the exception to the original question. – Impworks Mar 27 '13 at 21:12
  • 2
    Perhaps you did not read the last comment I left you on your previous question. I'll repeat it for you here: **Reflection.Emit is too weak to use to build a real compiler.** It's great for little toy compilation tasks like emitting dynamic call sites and expression trees in LINQ queries, but for the sorts of problems you'll face in a compiler you will quickly exceed its capabilities. Use CCI, not Reflection.Emit. – Eric Lippert Mar 27 '13 at 21:18
  • Whether it is possible to get out of this vicious circle or not I do not know. However, I can certainly give you examples of vicious circles that you actually cannot get out of with Reflection Emit. It falls down quickly when you make an even slightly complicated type topology. – Eric Lippert Mar 27 '13 at 21:20
  • @EricLippert, I have read the comment, but the advice to use CCI instead of Reflection.Emit is not very helpful since it means I pretty much have to rewrite most of my app from scratch. I'd love to see the examples of what is impossible to do with `Reflection.Emit` to avoid further failures. – Impworks Mar 27 '13 at 21:26
  • If you've chosen the wrong tool then the time you've wasted is water under the bridge. The sooner you start over using the right tool, the sooner you'll be done. – Eric Lippert Mar 27 '13 at 21:27
  • Here's an article dating from the last time a compiler developer asked me this question; in this case, VB compiler developer and my former colleague Lucian: http://blogs.msdn.com/b/lucian/archive/2009/11/29/the-limitations-of-reflection-emit.aspx – Eric Lippert Mar 27 '13 at 21:29
  • possible duplicate of [Reflection-generated and generic types](http://stackoverflow.com/questions/15646881/reflection-generated-and-generic-types) – Peter Ritchie Mar 27 '13 at 21:32
  • @EricLippert - Reflection.Emit may be inadequate for building a full-fidelity C# compiler, but that doesn't make it inappropriate for building other compilers. For simple source languages I think it may be a perfectly reasonable choice. Even something as complex as F# Interactive's REPL can be built on top of Reflection.Emit (though it _is_ possible to write some F# code that hits corner cases that can't be generated properly). – kvb Mar 29 '13 at 23:35
  • @kvb: Sure. The Roslyn C# repl uses Reflection.Emit as well, but it doesn't attempt to define types with interesting topologies. – Eric Lippert Mar 30 '13 at 00:54

1 Answers1

5

For some reason, you need to use the static overload of GetConstructor() to do this. In your case, the code could look like this:

var ctor = TypeBuilder.GetConstructor(
    tupleType, typeof(Tuple<,>).GetConstructors().Single());
svick
  • 236,525
  • 50
  • 385
  • 514