Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
189 views
in Technique[技术] by (71.8m points)

c# - Got TypeLoadException when emitting classes that reference each other in the generic argument of the base class

The following source code shows what I wanted to do. Create two classes dynamically inherited from a generic base class. And set each other's TypeBuilder to that generic parameter. Finally, call CreateType and TypeLoadException thrown.

The two classes need to know each other's Type because they have the Parent-Children relationship, and some library methods will check that generic parameter's Type to provide functions based on reflection.

(TypeLoadException: Could not load type 'Test.Type_2' from assembly 'DynamicClassTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.)

I have read this post and it did not help.

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

namespace Test
{
    public class BaseClass<T>
    {
    }

    static class Program
    {
        static void Main()
        {
            var assembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName($"DynamicClassTest"), AssemblyBuilderAccess.Run);
            var moduleBuilder = assembly.DefineDynamicModule($"DynamicTypes");

            var typeBuilder1 = moduleBuilder.DefineType("Test.Type_1", TypeAttributes.Public);
            var typeBuilder2 = moduleBuilder.DefineType("Test.Type_2", TypeAttributes.Public);

            typeBuilder1.SetParent(typeof(BaseClass<>).MakeGenericType(typeBuilder2));
            typeBuilder2.SetParent(typeof(BaseClass<>).MakeGenericType(typeBuilder1));

            var type1 = typeBuilder1.CreateType();
            var type2 = typeBuilder2.CreateType();
        }
    }
}

If I change the SetParent to the following source code(self-reference), it would work well, but what I wanted to do is to reference each other.

typeBuilder1.SetParent(typeof(BaseClass<>).MakeGenericType(typeBuilder1));
typeBuilder2.SetParent(typeof(BaseClass<>).MakeGenericType(typeBuilder2));

Any ideas to fix this or I can work around it?

[Edit]

At this moment, I added two dynamic interfaces to avoid the problem. I must write more reflection logic to get the real class type which implemented the interface to make them work properly. But what I wanted to do is achieved.

Anyway, any better ideas will be welcomed.

var typeBuilder1_IF = moduleBuilder.DefineType("Test.Type_1_IF", TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract);
var typeBuilder2_IF = moduleBuilder.DefineType("Test.Type_2_IF", TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract);
    
var type1_IF = typeBuilder1_IF.CreateType();
var type2_IF = typeBuilder2_IF.CreateType();

var typeBuilder1 = moduleBuilder.DefineType("Test.Type_1", TypeAttributes.Public, typeof(BaseClass<>).MakeGenericType(type2_IF));
typeBuilder1.AddInterfaceImplementation(type1_IF);

var typeBuilder2 = moduleBuilder.DefineType("Test.Type_2", TypeAttributes.Public, typeof(BaseClass<>).MakeGenericType(type1_IF));
typeBuilder2.AddInterfaceImplementation(type2_IF);
    
var type1 = typeBuilder1.CreateType();
var type2 = typeBuilder2.CreateType();
question from:https://stackoverflow.com/questions/65900870/got-typeloadexception-when-emitting-classes-that-reference-each-other-in-the-gen

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...