c# - 忽略/覆盖 AttributeUsage 限制

标签 c# .net .net-core custom-attributes

我需要能够申请 DisplayAttribute到类,但它的 AttributeUsage 在当前的 .NET/.NET Core 版本中不允许这样做。看起来像这样has been remedied for .NET Core vNext ,但如果有一些解决方法能够以某种方式忽略或覆盖此限制,直到此更改进入 .NET 版本,这将非常有用。我能看到的唯一选择是重新实现整个东西(包括本地化),但我真的不想支持和测试它只是为了在 .NET vNext 出现后立即弃用它。

有什么聪明的想法/技巧吗?

AttributeUsage 限制是否在运行时由 CLR 验证,或者它们只是编译时限制?如果它们仅在编译时检查,那么是否有一种聪明的方法来更改编译器使用的元数据以“欺骗”它允许使用或以某种方式修改系统程序集以便我的开发机器允许使用?

*我似乎无法编辑赏金描述,所以只是为了澄清,赏金解决方案必须适用于 .NET Framework,奖励积分也适用于 .NET Core。

最佳答案

虽然您不应该更改现有的 .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 的情况下运行时,它将始终打印“no”(请注意,测试类使用我们的虚拟属性而不是真实属性):

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 weaver,将属性重写为真实的属性(hacky 代码传入):

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 支持 net core 并且修复是在 IL 级别,它应该可以正常工作。

关于c# - 忽略/覆盖 AttributeUsage 限制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51095264/

相关文章:

c# - Parallel.ForEach 花费的时间比预期的多

c# - 如何持久化实现状态模式的对象?

c# - 使用 SSH.NET 从 Ubuntu 服务器上的文件中删除行

c# - 如何删除数据集的列?

c# - VS2017 - 缺少 .net 核心 > 2.1 作为目标框架

c# - 在 WPF 中的某些情况下,上下文菜单被剪切

c# - 以编程方式确定当前域 Controller

c# - XmlSerializer。保留空字符串属性?

c# - 将 AddNLog 从 .NET Core 2.2 迁移到 3.0

c# - IDistributedCache 可用但数据不再在缓存中?