Игнорировать / переопределять ограничения AttributeUsage - PullRequest
0 голосов
/ 29 июня 2018

Мне нужно иметь возможность применять DisplayAttribute к классам, но его AttributeUsage не позволяет этого в текущей версии .NET / .NET Core. Похоже, что было исправлено для .NET Core vNext , но если есть какой-то обходной путь, позволяющий каким-то образом игнорировать или переопределять это ограничение, пока это изменение не попадет в выпуск .NET, который был бы чрезвычайно полезен , Единственный вариант, который я вижу, это переопределение всего этого (включая локализацию), но я действительно не хочу поддерживать и тестировать его, чтобы просто устареть, как только выйдет .NET vNext.

Какие-нибудь умные идеи / хаки?

Проверяются ли ограничения AttributeUsage во время выполнения CLR или они просто ограничивают время компиляции? Если они проверяются только во время компиляции, то существует ли умный способ изменить метаданные, используемые компилятором, чтобы «обмануть» их, разрешив использование или каким-либо образом изменив системную сборку, чтобы мои машины разработчика допускали использование?

* Кажется, я не могу отредактировать описание награды, чтобы просто уточнить, решение для награды должно работать для .NET Framework, бонусные баллы также для .NET Core.

Ответы [ 2 ]

0 голосов
/ 08 июля 2018

Хотя вы не должны изменять существующую сборку .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, оно должно работать без проблем.

0 голосов
/ 07 июля 2018

Я декомпилировал и добавил AttributeTargets.Class и перекомпилировал. Я изменил пространство имен на System.ComponentModel.MyDataAnnotations, чтобы избежать коллизий пространства имен. Если вам нужно изменить пространство имен или что-то еще, я могу отправить sln.

https://drive.google.com/open?id=1KR5OJwsOtGUdOBWIxBoXuDHuq4Nw-X7d

...