使用反射或 IL 将自定义属性添加到 ReturnParameter
Adding custom attributes to ReturnParameter using reflection or IL
我正在尝试使用 IL 在运行时创建一些类型。我有一个原件 MethodInfo
,我必须复制它。
var parameters = OriginalMethod.GetParameters();
MethodBuilder methodBuilder = Builder.DefineMethod(
$"<{OriginalMethod.Name}>k__BackingMethod",
OriginalMethod.Attributes,
CallingConventions.HasThis,
OriginalMethod.ReturnType,
parameters.Select(i => i.ParameterType).ToArray()
);
foreach (var attribute in OriginalMethod.GetCustomAttributesData().ToCustomAttributeBuilder())
methodBuilder.SetCustomAttribute(attribute);
foreach (var attribute in OriginalMethod.ReturnParameter.GetCustomAttributesData().ToCustomAttributeBuilder())
methodBuilder.SetCustomAttribute(attribute); // <---- Problem here
ILGenerator il = methodBuilder.GetILGenerator();
// Some code removed for brevity
return methodBuilder;
如您所见,我可以成功复制方法级别的自定义属性。我什至可以获取 ReturnParameter
上的属性。但是,我似乎无法向 ReturnAttribute
添加新属性。使用上面的代码,return 属性被用作常规方法属性。知道我该怎么做吗?
编辑:为 ToCustomAttributeBuilder
添加了代码
internal static CustomAttributeBuilder[] ToCustomAttributeBuilder(this IEnumerable<CustomAttributeData> CustomAttributes)
=> CustomAttributes.Select(attribute => attribute.ToCustomAttributeBuilder()).ToArray();
internal static CustomAttributeBuilder ToCustomAttributeBuilder(this CustomAttributeData CustomAttribute)
{
var attributeArgs = CustomAttribute.ConstructorArguments.Select(a => a.Value).ToArray();
var propertyArgs = CustomAttribute.NamedArguments.Where(i => i.MemberInfo is PropertyInfo);
var propertyInfos = propertyArgs.Select(a => (PropertyInfo)a.MemberInfo).ToArray();
var propertyValues = propertyArgs.Select(a => a.TypedValue.Value).ToArray();
var fieldArgs = CustomAttribute.NamedArguments.Where(i => i.MemberInfo is FieldInfo);
var namedFieldInfos = fieldArgs.Select(a => (FieldInfo)a.MemberInfo).ToArray();
var namedFieldValues = fieldArgs.Select(a => a.TypedValue.Value).ToArray();
return new CustomAttributeBuilder(CustomAttribute.Constructor, attributeArgs, propertyInfos, propertyValues, namedFieldInfos, namedFieldValues);
}
您需要将自定义属性应用于 return 值参数,而不是方法:
ParameterBuilder returnValueParameterBuilder =
methodBuilder.DefineParameter(0, ParameterAttributes.Retval, parameterName: null);
foreach (var attribute in OriginalMethod.ReturnParameter.GetCustomAttributesData()
.ToCustomAttributeBuilder())
{
returnValueParameterBuilder.SetCustomAttribute(attribute);
}
我正在尝试使用 IL 在运行时创建一些类型。我有一个原件 MethodInfo
,我必须复制它。
var parameters = OriginalMethod.GetParameters();
MethodBuilder methodBuilder = Builder.DefineMethod(
$"<{OriginalMethod.Name}>k__BackingMethod",
OriginalMethod.Attributes,
CallingConventions.HasThis,
OriginalMethod.ReturnType,
parameters.Select(i => i.ParameterType).ToArray()
);
foreach (var attribute in OriginalMethod.GetCustomAttributesData().ToCustomAttributeBuilder())
methodBuilder.SetCustomAttribute(attribute);
foreach (var attribute in OriginalMethod.ReturnParameter.GetCustomAttributesData().ToCustomAttributeBuilder())
methodBuilder.SetCustomAttribute(attribute); // <---- Problem here
ILGenerator il = methodBuilder.GetILGenerator();
// Some code removed for brevity
return methodBuilder;
如您所见,我可以成功复制方法级别的自定义属性。我什至可以获取 ReturnParameter
上的属性。但是,我似乎无法向 ReturnAttribute
添加新属性。使用上面的代码,return 属性被用作常规方法属性。知道我该怎么做吗?
编辑:为 ToCustomAttributeBuilder
internal static CustomAttributeBuilder[] ToCustomAttributeBuilder(this IEnumerable<CustomAttributeData> CustomAttributes)
=> CustomAttributes.Select(attribute => attribute.ToCustomAttributeBuilder()).ToArray();
internal static CustomAttributeBuilder ToCustomAttributeBuilder(this CustomAttributeData CustomAttribute)
{
var attributeArgs = CustomAttribute.ConstructorArguments.Select(a => a.Value).ToArray();
var propertyArgs = CustomAttribute.NamedArguments.Where(i => i.MemberInfo is PropertyInfo);
var propertyInfos = propertyArgs.Select(a => (PropertyInfo)a.MemberInfo).ToArray();
var propertyValues = propertyArgs.Select(a => a.TypedValue.Value).ToArray();
var fieldArgs = CustomAttribute.NamedArguments.Where(i => i.MemberInfo is FieldInfo);
var namedFieldInfos = fieldArgs.Select(a => (FieldInfo)a.MemberInfo).ToArray();
var namedFieldValues = fieldArgs.Select(a => a.TypedValue.Value).ToArray();
return new CustomAttributeBuilder(CustomAttribute.Constructor, attributeArgs, propertyInfos, propertyValues, namedFieldInfos, namedFieldValues);
}
您需要将自定义属性应用于 return 值参数,而不是方法:
ParameterBuilder returnValueParameterBuilder =
methodBuilder.DefineParameter(0, ParameterAttributes.Retval, parameterName: null);
foreach (var attribute in OriginalMethod.ReturnParameter.GetCustomAttributesData()
.ToCustomAttributeBuilder())
{
returnValueParameterBuilder.SetCustomAttribute(attribute);
}