忽略/覆盖 AttributeUsage 限制
Ignore / Override AttributeUsage Restrictions
我需要能够应用 DisplayAttribute
to classes but its AttributeUsage
doesn't allow that in the current .NET / .NET Core release. It looks like this has been remedied for .NET Core vNext,但如果有一些解决方法能够以某种方式忽略或覆盖此限制,直到此更改进入 .NET 版本,这将非常有用。我能看到的唯一选择是重新实现整个东西(包括本地化),但我真的不想支持和测试它只是为了在 .NET vNext 出现后立即弃用它。
有聪明的ideas/hacks吗?
AttributeUsage 限制是在运行时由 CLR 验证还是只是编译时限制?如果它们仅在编译时检查,那么是否有一种聪明的方法可以将编译器使用的元数据更改为 "trick" 允许使用或以某种方式修改系统程序集以便我的开发机器允许使用?
*我似乎无法编辑赏金描述,所以只是为了澄清一下,赏金解决方案必须适用于 .NET Framework,奖励积分也适用于 .NET Core。
我反编译并添加了AttributeTargets.Class并重新编译。
我将命名空间更改为 System.ComponentModel.MyDataAnnotations 以避免命名空间冲突。
如果您需要改回名称空间或其他东西,我可以发送 sln。
https://drive.google.com/open?id=1KR5OJwsOtGUdOBWIxBoXuDHuq4Nw-X7d
虽然您不应该更改现有的 .NET 程序集 - 由于签名和 GAC(麻烦等待),可以在编译后将属性添加到现有的 class 并且它可以正常工作。 AttributeUsage
似乎没有在运行时强制执行。
所以我创建了一个小的 Fody 插件,将某个属性重写到 DisplayAttribute
:
首先是我们将通过 Fody 重写的小虚拟属性:
[AttributeUsage (AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Class)]
public class DisplayPatchAttribute : Attribute
{
public DisplayPatchAttribute()
{
}
}
还有一个小虚拟程序,用于测试 DisplayAttribute
是否应用于测试 class。当 运行 没有 Fody-addin 它总是打印 "no" (注意测试 class 使用我们的虚拟属性而不是真实的):
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 级别,它应该可以正常工作。
我需要能够应用 DisplayAttribute
to classes but its AttributeUsage
doesn't allow that in the current .NET / .NET Core release. It looks like this has been remedied for .NET Core vNext,但如果有一些解决方法能够以某种方式忽略或覆盖此限制,直到此更改进入 .NET 版本,这将非常有用。我能看到的唯一选择是重新实现整个东西(包括本地化),但我真的不想支持和测试它只是为了在 .NET vNext 出现后立即弃用它。
有聪明的ideas/hacks吗?
AttributeUsage 限制是在运行时由 CLR 验证还是只是编译时限制?如果它们仅在编译时检查,那么是否有一种聪明的方法可以将编译器使用的元数据更改为 "trick" 允许使用或以某种方式修改系统程序集以便我的开发机器允许使用?
*我似乎无法编辑赏金描述,所以只是为了澄清一下,赏金解决方案必须适用于 .NET Framework,奖励积分也适用于 .NET Core。
我反编译并添加了AttributeTargets.Class并重新编译。 我将命名空间更改为 System.ComponentModel.MyDataAnnotations 以避免命名空间冲突。 如果您需要改回名称空间或其他东西,我可以发送 sln。
https://drive.google.com/open?id=1KR5OJwsOtGUdOBWIxBoXuDHuq4Nw-X7d
虽然您不应该更改现有的 .NET 程序集 - 由于签名和 GAC(麻烦等待),可以在编译后将属性添加到现有的 class 并且它可以正常工作。 AttributeUsage
似乎没有在运行时强制执行。
所以我创建了一个小的 Fody 插件,将某个属性重写到 DisplayAttribute
:
首先是我们将通过 Fody 重写的小虚拟属性:
[AttributeUsage (AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Class)]
public class DisplayPatchAttribute : Attribute
{
public DisplayPatchAttribute()
{
}
}
还有一个小虚拟程序,用于测试 DisplayAttribute
是否应用于测试 class。当 运行 没有 Fody-addin 它总是打印 "no" (注意测试 class 使用我们的虚拟属性而不是真实的):
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 级别,它应该可以正常工作。