Хотя вы не должны изменять существующую сборку .NET - из-за подписи и GAC (проблемы ожидают) можно добавить атрибут в существующий класс после компиляции, и он работает без проблем. AttributeUsage
, похоже, не применяется во время выполнения.
Итак, я создал небольшую надстройку Fody, которая переписывает определенный атрибут в DisplayAttribute
:
Сначала наш маленький атрибут-пустышка, который будет переписан через Fody:
[AttributeUsage (AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Class)]
public class DisplayPatchAttribute : Attribute
{
public DisplayPatchAttribute()
{
}
}
И небольшая фиктивная программа, которая проверяет, применяется ли DisplayAttribute
к тестовому классу. При запуске без Fody-addin всегда выводится «нет» (обратите внимание, что тестовый класс использует наш фиктивный атрибут вместо реального):
internal static class Program
{
private static void Main (string[] args)
{
var attr = Attribute.GetCustomAttribute (typeof(Test), typeof(DisplayAttribute)) as DisplayAttribute;
Console.WriteLine (attr == null ? "no" : "yes");
}
}
[DisplayPatch]
internal class Test
{
}
А теперь мы добавим небольшого ткача Fody, который переписывает атрибут в реальный (входящий хакерский код):
public class DisplayAttributeWeaver : BaseModuleWeaver
{
public override void Execute()
{
var dataAnnotationAssembly = ModuleDefinition.AssemblyReferences.First (e => e.Name.Contains ("DataAnnotation"));
var resolvedDataAnnotationAssembly = ModuleDefinition.AssemblyResolver.Resolve (dataAnnotationAssembly);
var displayAttribute = resolvedDataAnnotationAssembly.Modules.First().GetType ("System.ComponentModel.DataAnnotations.DisplayAttribute");
var displayAttributeConstructor = ModuleDefinition.ImportReference(displayAttribute.GetConstructors().First());
foreach (var type in ModuleDefinition.Types)
{
var targetAttribute = type.CustomAttributes.FirstOrDefault (e => e.AttributeType.Name == "DisplayPatchAttribute");
if (targetAttribute == null)
continue;
type.CustomAttributes.Remove (targetAttribute);
var newAttr = new CustomAttribute (displayAttributeConstructor);
type.CustomAttributes.Add (newAttr);
}
}
public override IEnumerable<string> GetAssembliesForScanning()
{
yield return "mscorlib";
yield return "System";
}
}
Преобразует DisplayPatchAttribute
в DisplayAttribute
, поэтому программа выводит "yes".
Тогда DisplayPatchAttribute
будет выглядеть как обычный DisplayAttribute
, и его свойства будут скопированы в новый атрибут.
Не проверено на .NET Core, но поскольку Fody поддерживает сетевое ядро и исправление на уровне IL, оно должно работать без проблем.