我创建了一个生成器类,它基于实现接口的接口构建代理类。
请参阅Build a Proxy class based on Interface without implementing 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]);
记住,我不知道给出了什么。
答案 0 :(得分:4)
这不是一般解决方案,但是如果您愿意将支持的属性约束到具有无参数构造函数和读/写属性和字段的属性
,那么它将起作用。CustomAttributeBuilder BuildCustomAttribute(System.Attribute attribute)
{
Type type = attribute.GetType();
var constructor = type.GetConstructor(Type.EmptyTypes);
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance);
var propertyValues = from p in properties
select p.GetValue(attribute, null);
var fieldValues = from f in fields
select f.GetValue(attribute);
return new CustomAttributeBuilder(constructor,
Type.EmptyTypes,
properties,
propertyValues.ToArray(),
fields,
fieldValues.ToArray());
}
要做一般解决方案,您可以使用表达式。这更复杂,但允许语法如下:
BuildCustomAttribute(() => new ObsoleteAttribute("Demo", true));
解析表达式以提取构造函数信息和参数将是复杂的部分,但它可以完成。
CustomAttributeBuilder BuildCustomAttribute(Expression<Action> exp)
{
//extract ConstructorInfo from exp
//extract ParameterValues from exp
//extract Attribute Type from exp
return new CustomAttributeBuilder(ConstructorInfo, ParameterValues);
}
答案 1 :(得分:1)
谢谢乔,
由于您的意见,我确实在Attribute Builder找到Expression
解决方案
我现在愿意更努力地让其他开发人员更容易使用我的Proxy。
我希望它可以更容易,如果我有属性实例,为什么我不能按原样使用它并应用属性?
如果您的解决方案没有Expression
,我很乐意听到。
以下是基于Attribute Builder的Expression
我的解决方案:
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;
}
答案 2 :(得分: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]));