首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >IL发出TypeBuilder和解析引用

IL发出TypeBuilder和解析引用
EN

Stack Overflow用户
提问于 2011-07-26 14:44:11
回答 2查看 532关注 0票数 3

我正在发布几个类,其中一些类需要在自己的构造函数中构造它们的对等类。不存在无限的递归依赖关系(因此,如果A构造B,B不会构造A;这对于嵌套引用也是如此,A构造B构造C意味着B或C都不会构造A)。目前,我正在编写发出构造函数的代码,我遇到了一些问题。我不知道先依赖的顺序,所以我似乎有几种选择:

通过某种方式,依赖项( defined.

  • Somehow

  • )对类进行排序,并按照依赖项的顺序“构建”类,因此更依赖的类有一个有效的构造函数引用来抓取。

  • 在第一次传递时分别定义所有构造函数(实际上没有为方法释放IL ),因此所有构造函数引用都是

  • 缓存已定义的构造函数,因此如果构造函数尚未定义,我可以创建一个place-holder ConstructorBuilder来获取引用,然后在最后发出构造函数时捕获引用。

我目前正在尝试选项(3),我想知道是否已经有一种方法可以从TypeBuilder中实现。我有如下代码(在需要时获取构造函数引用):

代码语言:javascript
复制
            var fieldType = DefineType(udtField.Type); // This looks up a cached TypeBuilder or creates a placeholder, if needed
            var constructor = fieldType.GetConstructor(Type.EmptyTypes);
            if (constructor == null)
            {
                constructor =
                    fieldType.DefineConstructor(
                        MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
                        CallingConventions.Standard, Type.EmptyTypes);
            }

目前,我的构建方法是这样启动的(如果之前定义了构造函数,我认为这是行不通的):

代码语言:javascript
复制
    private void BuildConstructor()
    {
        var method =
            DefinedType.DefineConstructor(
                MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
                CallingConventions.Standard, Type.EmptyTypes);
        var il = method.GetILGenerator();

有什么方法可以查找以前定义的ConstructorBuilder (如果已经定义的话),而不必创建自己的显式缓存?似乎TypeBuilder应该知道这一点,但是我看不到从TypeBuilder文档中查找它的任何明显方法。

编辑:

最后,我沿着路由(2)走,它定义了第一次传递过程中的所有相关方法,然后在第二次传递中释放IL。对于已经在其他地方定义的构建器,我仍然很好奇是否有可能从MethodBuilder实例(或ConstructorBuilder实例)中获得这些实例。

EN

回答 2

Stack Overflow用户

发布于 2011-07-26 14:57:08

我不是TypeBuilder方面的专家,但是它有一个方法.GetConstructor ( http://msdn.microsoft.com/en-us/library/cs01xzbk.aspx )和.GetMethod ( http://msdn.microsoft.com/en-us/library/4s2kzbw8.aspx ),如果在缓存的fieldType上调用它们,它应该能够返回声明的构造函数.

票数 0
EN

Stack Overflow用户

发布于 2017-01-09 09:46:51

通过查看TypeBuilder的反汇编代码,似乎不可能每种类型都需要一个以上的构造函数:

TypeBuilder.DefineConstructor只调用DefineConstructorNoLock,它只检查参数并增加constructorCount字段:

代码语言:javascript
复制
[SecurityCritical]
private ConstructorBuilder DefineConstructorNoLock(MethodAttributes attributes, CallingConventions callingConvention, Type[] parameterTypes, Type[][] requiredCustomModifiers, Type[][] optionalCustomModifiers)
{
    this.CheckContext(parameterTypes);
    this.CheckContext(requiredCustomModifiers);
    this.CheckContext(optionalCustomModifiers);
    this.ThrowIfCreated();
    string name;
    if ((attributes & MethodAttributes.Static) == MethodAttributes.PrivateScope)
    {
        name = ConstructorInfo.ConstructorName;
    }
    else
    {
        name = ConstructorInfo.TypeConstructorName;
    }
    attributes |= MethodAttributes.SpecialName;
    ConstructorBuilder result = new ConstructorBuilder(name, attributes, callingConvention, parameterTypes, requiredCustomModifiers, optionalCustomModifiers, this.m_module, this);
    this.m_constructorCount++;
    return result;
}

因此,如果您只想为每个类型定义一个构造函数,您可以检查这个属性(使用反射,因为它是一个私有字段)并检查它的值:

代码语言:javascript
复制
namespace ConsoleApplication7
{
    static class TypeBuilderExtension
    {
        public static int GetConstructorCount(this TypeBuilder t)
        {
            FieldInfo constCountField = typeof(TypeBuilder).GetField("m_constructorCount", BindingFlags.NonPublic | BindingFlags.Instance);
            return (int) constCountField.GetValue(t);
        }
    }

    class Program
    {  
        static void Main(string[] args)
        {
            AppDomain ad = AppDomain.CurrentDomain;
            AssemblyBuilder ab = ad.DefineDynamicAssembly(new AssemblyName("toto.dll"), AssemblyBuilderAccess.RunAndSave);
            ModuleBuilder mb = ab.DefineDynamicModule("toto.dll");
            TypeBuilder tb = mb.DefineType("mytype");
            
            Console.WriteLine("before constructor creation : " + tb.GetConstructorCount());

            ConstructorBuilder cb = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new Type[0]);
            ILGenerator ilgen = cb.GetILGenerator();
            ilgen.Emit(OpCodes.Ret);
            Console.WriteLine("after constructor creation : " + tb.GetConstructorCount());

            tb.CreateType();
            ab.Save("toto.dll");
        }
    }
}

其中产出:

构造函数创建前的

:0

构造函数创建后:1

这不会给出实际的ConstructorBuilder,但您将知道您已经定义了它。

如果您希望实际获得constructorBuilder,并且不希望创建过多的重载(例如1),我将使用扩展方法选择选项3:

代码语言:javascript
复制
    static class TypeBuilderExtension
    {
        private static Dictionary<TypeBuilder, ConstructorBuilder> _cache = new Dictionary<TypeBuilder, ConstructorBuilder>();

        public static ConstructorBuilder DefineMyConstructor(this TypeBuilder tb)
        {
            if (!_cache.ContainsKey(tb))
            {
                _cache.Add(tb, tb.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new Type[0]));
            }

            return _cache[tb];
        }
    }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6831859

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档