我正在使用Mono.Cecil自动生成(很多简单,通用的)工厂方法,从而为库提供方便的API。 为标记有特殊自定义属性的属性生成工厂。 要生成它们,我必须知道此类属性的类型。 非通用情况很简单:

ModuleDefinition module = /* obtained from ReadAssembly */
foreach (var type in module.Types)
    if (/* type is marked with the right attribute */)
        foreach (var prop in type.Properties)
            if (/* prop is marked with the right attribute */)
                GenerateFactory(type, prop, prop.PropertyType);

但是,标记的某些类型实际上是泛型。 在这种情况下,类型上的属性包含应为其创建工厂的通用参数,如下所示:

[EmitFactories(typeof(int))]
public class Class<T>
{
    [MagicProperty]
    T Property { get; set; }
}

(在这里,我希望为Class<int>.Property工厂)。 我通过将typeGenericInstanceType处理这种情况。 但是,我无法获得属性的类型-枚举type.Properties我需要首先调用Resolve() ,它会丢失所有通用信息。 然后,属性类型为T (而不是int ),这当然会使后面的代码失败。

Mono.Cecil具有GenericInstanceTypeGenericInstanceMethod ,但是属性没有等效项。 我尝试使用module.Import(prop.PropertyType, type) (将type作为通用参数提供程序),但这是行不通的。

您对如何解决实际的物业类型有任何想法吗? 请注意,它可以与TT本身完全无关,也可以将T埋入内部(例如List<T> )。 理想情况下,它可以在给定typeTypeReference情况下工作-这样,我就不必为非泛型和泛型情况编写单独的代码。

===============>>#1 票数:1

基于https://stackoverflow.com/a/16433452/613130 (可能基于https://groups.google.com/d/msg/mono-cecil/QljtFf_eN5I/YxqLAk5lh_cJ) ,应为:

using System;
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Rocks;

namespace Utilities
{
    public class EmitFactoriesAttribute : Attribute
    {
        public readonly Type[] Types;

        public EmitFactoriesAttribute()
        {
        }

        public EmitFactoriesAttribute(params Type[] types)
        {
            Types = types;
        }
    }

    public class MagicPropertyAttribute : Attribute
    {
    }

    public static class EmitFactories
    {
        public static void WorkOnAssembly(string path)
        {
            AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly("ConsoleApplication4.exe");

            ModuleDefinition module = assembly.MainModule;

            TypeDefinition emitFactoriesAttribute = module.Import(typeof(EmitFactoriesAttribute)).Resolve();
            TypeDefinition magicPropertyAttribute = module.Import(typeof(MagicPropertyAttribute)).Resolve();

            foreach (TypeDefinition type in module.Types)
            {
                CustomAttribute emitFactory = type.CustomAttributes.SingleOrDefault(x => x.AttributeType.MetadataToken == emitFactoriesAttribute.MetadataToken);

                if (emitFactory == null)
                {
                    continue;
                }

                TypeReference typeRef = type;

                TypeReference[] replacementTypes;

                if (emitFactory.ConstructorArguments.Count != 0)
                {
                    var temp = ((CustomAttributeArgument[])emitFactory.ConstructorArguments[0].Value);
                    replacementTypes = Array.ConvertAll(temp, x => (TypeReference)x.Value);
                }
                else
                {
                    replacementTypes = new TypeReference[0];
                }

                if (replacementTypes.Length != type.GenericParameters.Count)
                {
                    throw new NotSupportedException();
                }

                if (replacementTypes.Length != 0)
                {
                    typeRef = typeRef.MakeGenericInstanceType(replacementTypes);
                }

                foreach (PropertyDefinition prop in type.Properties)
                {
                    CustomAttribute magicProperty = prop.CustomAttributes.SingleOrDefault(x => x.AttributeType.MetadataToken == magicPropertyAttribute.MetadataToken);

                    if (magicProperty == null)
                    {
                        continue;
                    }

                    MethodReference getter = prop.GetMethod;
                    MethodReference setter = prop.SetMethod;

                    if (replacementTypes.Length != 0)
                    {
                        if (getter != null)
                        {
                            getter = getter.MakeHostInstanceGeneric(replacementTypes);
                        }

                        if (setter != null)
                        {
                            setter = setter.MakeHostInstanceGeneric(replacementTypes);
                        }
                    }
                }
            }
        }
    }

    public static class TypeReferenceExtensions
    {
        // https://stackoverflow.com/a/16433452/613130
        public static MethodReference MakeHostInstanceGeneric(this MethodReference self, params TypeReference[] arguments)
        {
            var reference = new MethodReference(self.Name, self.ReturnType, self.DeclaringType.MakeGenericInstanceType(arguments))
            {
                HasThis = self.HasThis,
                ExplicitThis = self.ExplicitThis,
                CallingConvention = self.CallingConvention
            };

            foreach (var parameter in self.Parameters)
                reference.Parameters.Add(new ParameterDefinition(parameter.ParameterType));

            foreach (var generic_parameter in self.GenericParameters)
                reference.GenericParameters.Add(new GenericParameter(generic_parameter.Name, reference));

            return reference;
        }
    }

    // Test
    [EmitFactories(typeof(int), typeof(long))]
    public class Class<TKey, TValue>
    {
        [MagicProperty]
        Dictionary<TKey, TValue> Property1 { get; set; }

        [MagicProperty]
        List<TValue> Property2 { get; set; }
    }
}

您尚未定义EmitFactoriesAttribute ,所以我将其编写为EmitFactoriesAttribute(params Type[] types) ,以便能够接受Class<TKey, TValue>这样的情况的多个替换。

最后,我不会直接操纵该属性:我正在操纵它的getter和setter。

我无法测试,因为我没有工厂...

  ask by Grzegorz Herman translate from so

未解决问题?本站智能推荐:

1回复

如何将值存储到泛型类字段(Mono.Cecil)

我正在使用Mono.Cecil来重写一些程序集。 给定一个带有字符串字段的泛型类。 我想在这个类的方法中生成代码,该类写入该字段。 这是实现这一目标的代码: 对于非泛型类,它就像一个魅力。 对于泛型类,它会产生错误的IL。 如果您查看反编译的IL,您可以发现与编译器发出的相同指
1回复

试图引用Task.ContinueWith 来自Mono.Cecil

问题 我正在尝试使用严格的Mono.Cecil获取此IL指令。 现在,我找到的唯一解决方案涉及导入每个引用程序集及其导出的类型,调用MakeGenericInstanceType()和Module.Import() 。 想要IL指令 它产生的代码是: 我能得到什么(
1回复

用Cecil调用EqualityComparer.Default

如何生成必要的IL代码以使用Mono Cecil调用System.Collections.Generic.EqualityComparer<T>.get_Default方法? 我已经尝试过类似的变体,但是遇到了各种各样的错误,从PEVerify无法解析令牌,到Cecil抱怨某些
1回复

从Mono.Cecil中的引用获取成员定义

我注意到,某些类型的方法(例如,通用类型的方法)中的字段或方法引用将是FieldReference类型,而不是FieldDefinition尽管该字段(或方法)在同一模块中,并且是同一类型。 我怎样才能获得FieldDefinition从这个FieldReference ? 我试图mod
1回复

在Fody / Mono.Cecil中获取CustomAttribute的SequencePoint

我正在编写Fody Addin,可以注入代码并向用户提供错误消息。 我能够确定指令的顺序点,但是找不到找到CustomAttributes顺序点的方法。 我需要获取此信息,以便在错误应用属性的情况下为调试器提供一个提示,以在哪里找到错误的位置。 所以基本上我有这样的事情:
1回复

检查属性类型是否使用Mono.Cecil重载==运算符

我正在使用Mono.Cecil编写一个将一些IL代码注入属性设置器的程序。 问题是我需要在IL上对属性使用相等运算符。 例如: 我需要在这些setter中注入的IL代码是这样的: Property2 。 问题在于Property2是string类型,该类型的string重载
2回复

Mono.Cecil - 如何获取自定义属性

我试图使用Cecil检查与给定方法相关的属性。 它似乎找到了它,但我无法使用以下代码获取其名称: 我知道这必须是我设置我的函数的属性,因为当我从dll中删除它时,第二行代码将变为null。 我想做的是能够获得属性的名称。 目前第二行代码只返回一个“Mono.Cecil.Custom
1回复

使用Mono.Cecil获取类型的已实现接口

抱歉,如果这个问题听起来很琐碎,我已经阅读了许多有关该问题的讨论,但我不能百分百确定自己是否正确: 我想获取所有由类实现的接口,然后可以使用以下代码: 因此,变量“ interfaceList”现在应该包含所有由“ typeItem”实现的接口-无论接口是显式还是隐式实现都无关紧要
4回复

Mono.Cecil类型.IsAssignableFrom(derivedType)等效

我正在使用Mono.Cecil在Assembly中查找从给定派生的类型。 通常,可以使用IsAssignableFrom()方法完成此操作,但是我无法在Cecil中实现它的等效功能。 有没有这样的方法或其他方式进行检查? 谢谢迈克
1回复

如何使用mono.cecil在类型中按类型查找变量?

我在这里浏览了有关cecil的问题,关于这个特定问题,我什么也没看到。 我想要实现的是在method.Body.Variables中找到某个类型的变量(在我的情况下为System.Exception ) 我写了以下代码,认为可以解决问题: 尽管我确定原因是我对cecil的不信