创建规则以对参数属性强制执行默认值

Create a rule to enforce defaults on an Parameter attribute

我正在查看 CallerMemberName 属性。当您指定这样的方法时

public void TraceInfo(string propertyName, [CallerMemberName] string memberName)  

我们收到一个编译时错误,指出

Parameter with caller info must have a default value

CallerMemberName 属性是密封的,我想强制使用这样的默认参数 class

如何在常规属性上执行相同的默认属性 class?

[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
public sealed class DefaultEnforcedAttribute : Attribute
{
    public DefaultEnforcedAttribute()
    {
    }
}

属性为 [CallerMemberName] 的参数必须是可选的。这允许您在调用方法时省略此参数。然后C#会自动用调用者成员名填充这个参数。

public void TraceInfo(string propertyName, [CallerMemberName] string memberName = null) 

您不能在编译时强制执行此规则,因为这会涉及一些编译器魔术,但您可以在属性的代码中(例如在静态构造函数中)进行一些反射。您将不得不枚举类型及其方法。

像这样:

var faultyProps = assembly.GetTypes()
    .SelectMany(t => t.GetMethods())
    .SelectMany(m => m.GetParameters())
    .Where(p => p.GetCustomAttribute<DefaultEnforcedAttribute>() != null && !p.IsOptional);

这些验证是在编译时完成的,因此,它们应该由编译器实现。

好消息是自编译器平台 Roslyn 诞生以来,您可以实现 visitors,这样您就可以使用您的自定义扩展 C# 编译器验证。

我会开始阅读这些其他问答以查看使用 Roslyn 检查内容的示例:

  • How to check if a property is decorated with a custom attribute using Roslyn?
  • How to get all properties that are anotated with some attribute?

此外,您应该阅读 Roslyn 的官方文档,特别是这篇文章:Getting Started C# Syntax Analysis. Also see C# and Visual Basic - Use Roslyn to Write a Live Code Analyzer for Your API

最后,您可能需要下载并安装 .NET Compiler Platform SDK

方法 #2 适用于那些不喜欢必须在多台机器上安装 Visual Studio 扩展程序的人

另一种将作为项目构建的一部分集成的老派方法可以是 MSBuild 目标,调用在 C# 中实现的 MSBuild 任务,该任务可以加载使用 AfterTargets 属性构建的程序集在 <Target> 上,值为 "AfterBuild"。它将如下所示:

<Target Name="EnforcePostCompilationRules" AfterTargets="AfterBuild">
     <EnforceMethodParameterDefaultValue />
</Target>

该任务将加载整个程序集并使用反射查找所有类型,其方法具有使用某些属性的参数。如果某些参数具有强制执行默认参数值的属性,但参数 没有默认值,则会抛出构建错误,并显示一条有意义的消息,指出哪个方法未通过整个验证。

方法 #3:使用 NuGet 安装 Roslyn 扩展

也许您对 Roslyn 为您带来的更广泛的可能性感到兴奋。检查此问答,其中有人回答说安装 Visual Studio 扩展是可能的,将其包装为 NuGet 包:

  • NuGet Package which installs a VSIX