While you should not change an existing .NET Assembly - due to signing and the GAC (trouble awaits) it is possible to add the attribute onto an existing class after compiling and it works without problems. The AttributeUsage
does not seem to be enforced at runtime.
So I created a little Fody add-in that rewrites a certain attribute to the DisplayAttribute
:
First our little dummy attribute that will be rewritten through Fody:
[AttributeUsage (AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Class)]
public class DisplayPatchAttribute : Attribute
{
public DisplayPatchAttribute()
{
}
}
And a little dummy program that tests whether the DisplayAttribute
is applied to a test class. When ran without the Fody-addin it will always print "no" (Note that the test class uses our dummy attribute instead of the real one):
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
{
}
And now we add a little Fody weaver that rewrites the attribute to the real one (hacky code incoming):
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";
}
}
It converts the DisplayPatchAttribute
into a DisplayAttribute
and so the program outputs "yes".
The DisplayPatchAttribute
would then look like the normal DisplayAttribute
and have its properties copied over to the new attribute.
Not tested for .NET Core but as Fody supports net core and the fix is on IL level it should work without problems.