5

インターフェイスを実装するインターフェイスに基づいてプロキシ クラスを構築するジェネレーター クラスを作成しました。

Build a Proxy class based on Interface without implement it に関する私の投稿を参照してください。

CustomAttributeData.GetCustomAttributes(MemberInfo target)インターフェイスのメンバーを読み取り、それらをプロキシにインポートすることに成功したときに使用しました。

実行時に生成されたクラスに追加の属性を挿入したいと考えています。属性インスタンスがそれらをプロキシに挿入するように求めています。

例えば:

開発者はこれを値として渡すことができます: new ObsoleteAttribute("Demo", true), (空のコンストラクターがありますが、プロパティは読み取り専用です)、次のように変換したいと思います:

return new CustomAttributeBuilder(
               attribute.GetType().GetConstructor(Type[] {typeof (string), typeof (bool)}),
               new object[] {"Demo", true},
               new FieldInfo[0], 
               new object[0]);

覚えておいてください、私は何が与えられたのか分かりません。

4

3 に答える 3

3

Joe さん、ありがとうございます。ご意見のおかげで、 Attribute Builderで解決策を
見つけました。 他の開発者が私のProxyを使いやすくするために、もう少し努力したいと思っています。Expression

もっと簡単にできるといいのですが、属性インスタンスがあれば、それをそのまま使用して属性を適用できないのはなぜですか?

なしで解決策がある場合はExpression、ぜひお知らせください。

Attribute BuilderExpressionに基づく私のソリューションは次のとおりです。

private CustomAttributeBuilder GetCustumeAttributeBuilder(Expression<Func<Attribute>> attributeExpression)
{
    ConstructorInfo constructor = null;
    List<object> constructorArgs = new List<object>();
    List<PropertyInfo> namedProperties = new List<PropertyInfo>();
    List<object> propertyValues = new List<object>();
    List<FieldInfo> namedFields = new List<FieldInfo>();
    List<object> fieldValues = new List<object>();

    switch (attributeExpression.Body.NodeType)
    {
        case ExpressionType.New:
            constructor = GetConstructor((NewExpression)attributeExpression.Body, constructorArgs);
            break;
        case ExpressionType.MemberInit:
            MemberInitExpression initExpression = (MemberInitExpression)attributeExpression.Body;
            constructor = GetConstructor(initExpression.NewExpression, constructorArgs);

            IEnumerable<MemberAssignment> bindings = from b in initExpression.Bindings
                                                        where b.BindingType == MemberBindingType.Assignment
                                                        select b as MemberAssignment;

            foreach (MemberAssignment assignment in bindings)
            {
                LambdaExpression lambda = Expression.Lambda(assignment.Expression);
                object value = lambda.Compile().DynamicInvoke();
                switch (assignment.Member.MemberType)
                {
                    case MemberTypes.Field:
                        namedFields.Add((FieldInfo)assignment.Member);
                        fieldValues.Add(value);
                        break;
                    case MemberTypes.Property:
                        namedProperties.Add((PropertyInfo)assignment.Member);
                        propertyValues.Add(value);
                        break;
                }
            }
            break;
        default:
            throw new ArgumentException("UnSupportedExpression", "attributeExpression");
    }

    return new CustomAttributeBuilder(
        constructor,
        constructorArgs.ToArray(),
        namedProperties.ToArray(),
        propertyValues.ToArray(),
        namedFields.ToArray(),
        fieldValues.ToArray());
}

private ConstructorInfo GetConstructor(NewExpression expression, List<object> constructorArgs)
{
    foreach (Expression arg in expression.Arguments)
    {
        LambdaExpression lambda = Expression.Lambda(arg);
        object value = lambda.Compile().DynamicInvoke();
        constructorArgs.Add(value);
    }
    return expression.Constructor;
}
于 2013-04-11T06:11:08.480 に答える
0

質問を正しく理解していれば、生成された型にカスタム属性が追加されるはずです

public class CustomAttribute: System.Attribute
{
    public CustomAttribute()
    {
    }
}

TypeBuilder typeBuilder = module.DefineType(...)

....

typeBuilder.SetCustomAttribute(new CustomAttributeBuilder(
    typeof(CustomAttribute).GetConstructor(Type.EmptyTypes), 
    Type.EmptyTypes, 
    new FieldInfo[0], 
    new object[0]));
于 2013-04-09T23:18:43.237 に答える