Fac*_*Vir 16 c# generics reflection.emit
这段代码片段是我的类生成代码的简化摘录,它创建了两个类,它们作为泛型类型中的参数相互引用:
namespace Sandbox
{
using System;
using System.Reflection;
using System.Reflection.Emit;
internal class Program
{
private static void Main(string[] args)
{
var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Run);
var module = assembly.DefineDynamicModule("Test");
var typeOne = module.DefineType("TypeOne", TypeAttributes.Public);
var typeTwo = module.DefineType("TypeTwo", TypeAttributes.Public);
typeOne.DefineField("Two", typeof(TestGeneric<>).MakeGenericType(typeTwo), FieldAttributes.Public);
typeTwo.DefineField("One", typeof(TestGeneric<>).MakeGenericType(typeOne), FieldAttributes.Public);
typeOne.CreateType();
typeTwo.CreateType();
Console.WriteLine("Done");
Console.ReadLine();
}
}
public struct TestGeneric<T>
{
}
}
Run Code Online (Sandbox Code Playgroud)
哪个应该产生相当于以下的MSIL:
public class TypeOne
{
public Program.TestGeneric<TypeTwo> Two;
}
public class TypeTwo
{
public Program.TestGeneric<TypeOne> One;
}
Run Code Online (Sandbox Code Playgroud)
但是反而抛出了这个异常typeOne.CreateType():
System.TypeLoadException was unhandled
Message=Could not load type 'TypeTwo' from assembly 'Test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
Source=mscorlib
TypeName=TypeTwo
StackTrace:
at System.Reflection.Emit.TypeBuilder.TermCreateClass(RuntimeModule module, Int32 tk, ObjectHandleOnStack type)
at System.Reflection.Emit.TypeBuilder.CreateTypeNoLock()
at System.Reflection.Emit.TypeBuilder.CreateType()
at Sandbox.Program.Main(String[] args) in C:\Users\aca1\Code\Sandbox\Program.cs:line 20
Run Code Online (Sandbox Code Playgroud)
有趣的事情要注意:
One在TypeTwo创建TypeOne之前TypeTwo仍然失败,但TypeTwo在TypeOne成功之前创建.因此,异常是由于在通用字段类型中使用尚未创建的类型而引起的; 但是,因为我需要使用循环引用,所以我无法通过按特定顺序创建类型来避免这种情况.TestGeneric<>类型并将字段声明为TypeOne&TypeTwo直接不会产生此错误; 因此我可以使用已定义但未创建的动态类型.TestGeneric<>从a 更改struct为a class不会产生此错误; 所以这种模式也与大多数仿制药的工作,只是没有通用的值类型.TestGeneric<>我的情况下的声明,因为它在另一个程序集中声明 - 特别是System.Data.Linq.EntityRef<>在System.Data.Linq.dll中声明.TestGeneric<>在Program中作为嵌套类型,因此它继承了internal可见性.我现在已经在上面的代码示例中解决了这个问题,它实际上确实有效.关于a)为什么会发生这种情况的任何想法,b)我如何解决这个问题和/或c)我如何解决这个问题?
谢谢.
Sco*_*ott 10
我不知道为什么会发生这种情况.我猜得很好.
正如您所观察到的,创建泛型类的方式与创建泛型结构的方式不同.当您创建类型'TypeOne'时,发射器需要创建泛型类型'TestGeneric',并且由于某种原因需要正确的Type而不是TypeBuilder.当尝试确定新通用结构的大小时,可能会发生这种情况?我不确定.也许TypeBuilder无法确定其大小,因此需要创建"TypeTwo"类型.
当找不到TypeTwo时(因为它只作为TypeBuilder存在),将触发AppDomain的TypeResolve事件.这使您有机会解决问题.在处理TypeResolve事件时,您可以创建类型"TypeTwo"并解决问题.
这是一个粗略的实现:
namespace Sandbox
{
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
internal class Program
{
private static void Main(string[] args)
{
var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Run);
var module = assembly.DefineDynamicModule("Test");
var typeOne = module.DefineType("TypeOne", TypeAttributes.Public);
var typeTwo = module.DefineType("TypeTwo", TypeAttributes.Public);
typeOne.DefineField("Two", typeof(TestGeneric<>).MakeGenericType(typeTwo), FieldAttributes.Public);
typeTwo.DefineField("One", typeof(TestGeneric<>).MakeGenericType(typeOne), FieldAttributes.Public);
TypeConflictResolver resolver = new TypeConflictResolver();
resolver.AddTypeBuilder(typeTwo);
resolver.Bind(AppDomain.CurrentDomain);
typeOne.CreateType();
typeTwo.CreateType();
resolver.Release();
Console.WriteLine("Done");
Console.ReadLine();
}
}
public struct TestGeneric<T>
{
}
internal class TypeConflictResolver
{
private AppDomain _domain;
private Dictionary<string, TypeBuilder> _builders = new Dictionary<string, TypeBuilder>();
public void Bind(AppDomain domain)
{
domain.TypeResolve += Domain_TypeResolve;
}
public void Release()
{
if (_domain != null)
{
_domain.TypeResolve -= Domain_TypeResolve;
_domain = null;
}
}
public void AddTypeBuilder(TypeBuilder builder)
{
_builders.Add(builder.Name, builder);
}
Assembly Domain_TypeResolve(object sender, ResolveEventArgs args)
{
if (_builders.ContainsKey(args.Name))
{
return _builders[args.Name].CreateType().Assembly;
}
else
{
return null;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1639 次 |
| 最近记录: |