none
"Type must be provided by the runtime" exception when trying to instantiate a Roslyn-emitted class referencing a generic type with Roslyn-emitted type parameter

    Question

  • I have the following test which fails with the September 2012 CTP, but shouldn't, as far as I can tell:

    using System;
    using System.Linq;
    using System.Reflection;
    using System.Reflection.Emit;
    using NUnit.Framework;
    using Roslyn.Compilers;
    using Roslyn.Compilers.CSharp;
    
    namespace Tests
    {
        [TestFixture]
        public class TestRoslyn
        {
            [Test]
            public void TestGenerics()
            {
                var code = @"
    using Tests;
    using System.Collections.Generic;
    using System;
    
    public class DerivedClass : TestBaseClass {
        public override object Test() {
            return new List<DerivedClass>();
        }
    }
    ";
    
                var syntaxTree = SyntaxTree.ParseText(code);
    
                var compilation = Compilation.Create("DerivedClass")
                                             .WithOptions(new CompilationOptions(OutputKind.DynamicallyLinkedLibrary))
                                             .AddSyntaxTrees(syntaxTree)
                                             .AddReferences(
                                                 MetadataReference.CreateAssemblyReference("mscorlib"),
                                                 MetadataReference.CreateAssemblyReference("System"),
                                                 MetadataReference.CreateAssemblyReference("System.Core"),
                                                 new MetadataFileReference(typeof (TestBaseClass).Assembly.Location));
                    
    
                var assemblyBuilder =
                    AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("DynamicAssembly" + Guid.NewGuid()),
                                                                  AssemblyBuilderAccess.RunAndCollect);
                var moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicModule");
    
                var result = compilation.Emit(moduleBuilder);
    
                var type = moduleBuilder.GetTypes().FirstOrDefault(t => (typeof(TestBaseClass).IsAssignableFrom(t)));
    
                var instance = (TestBaseClass)Activator.CreateInstance(type);
    
                Assert.IsNotNull(instance);
                Assert.IsNotNull(instance.Test());
            }
        }
    
        public class TestBaseClass
        {
            public virtual object Test()
            {
                return null;
            }
        }
    }

    An ArgumentException is thrown at the line 

    (TestBaseClass)Activator.CreateInstance(type);

    with the message "Type must be a type provided by the runtime".

    That exception is triggered by the line 

    return new List<DerivedClass>();

    in the code I'm compiling with Roslyn.

    If I write "return new List<int>()", for example, then all is well. Using any type in an existing assembly as a type parameter to the generic type also succeeds. It is when the type parameter in the generic type is itself contained in the code I'm compiling that I get this exception.

    Also I notice that result.IsUncollectible returns false in cases where the ArgumentException is thrown. This seems to be a bug too, as Collectible Assemblies for Dynamic Type Generation doesn't say anything about generic types preventing assemblies from being collectible.

    Are these issues already known, and is there currently a workaround? I guess declaring closed generic types in a pre-compiled assembly would do it, but my actual scenario involves anonymous types, so that won't work for me.



    • Edited by Samuel Jack Monday, January 28, 2013 12:09 PM Clarified title
    Tuesday, January 22, 2013 9:11 AM

All replies

  • Anybody? Surely my scenario can't be that far off the beaten track?
    Monday, January 28, 2013 12:07 PM
  • This is a bug in Reflection.Emit APIs. Unfortunately using Reflection.Emit is the only way how to produce collectible code. So although Collectible Assemblies don't have limitations on generic types the limitations are imposed by bugs in Reflection.Emit.


    As a workaround you might be able to create a factory like so:

    using Tests;
    using System.Collections.Generic;
    using System;

    public static class Factory
    {
        public static object CreateList<T>()
        {
            return new List<T>();
        }
    }

    public class DerivedClass : TestBaseClass {
        public override object Test() {
            return Factory.CreateList<DerivedClass>();
        }
    }

    Friday, February 01, 2013 5:09 PM
  • The factory can also return List<T>.
    Friday, February 01, 2013 5:10 PM
  • Thanks for the confirmation of the bug, and suggested workaround. Unfortunately, I don't it will work in my specific case because I'm actually writing Linq queries involving anonymous types. When do you think the Reflection.Emit bug will be fixed? Any chance it might be in the next .Net 4.5 update?
    Friday, February 01, 2013 7:41 PM