如何在C#中创建自定义ObsoleteAttribute以触发使用时编译警告
自定义带固定消息的“过时”编译警告需求
我希望复用固定的过时提示消息,避免在每个ObsoleteAttribute中重复编写相同内容。于是我自定义了如下属性:
[AttributeUsage(AttributeTargets.Property)] public class MyObsoleteAttribute : Attribute { private const string CustomMessage = "This is a custom warning message"; public MyObsoleteAttribute() { Console.WriteLine(CustomMessage); } } public class MyClass { [MyObsolete] public string? Foo { get; set; } [MyObsolete] public string? Bar { get; set; } [MyObsolete] public string? FooBar { get; set; } }
但原生ObsoleteAttribute是sealed无法继承,导致使用标记了MyObsoleteAttribute的属性时,无法像原生Obsolete那样触发编译警告。比如以下代码应该触发警告,但目前没有任何提示:
var myClass = new MyClass(); var foo = myClass.Foo; var bar = myClass.Bar; var fooBar = myClass.FooBar;
解决方案
方案一:Roslyn分析器(跨VS/Rider,编译级警告)
通过编写Roslyn分析器,可以在编译阶段检测到标记了MyObsoleteAttribute的成员使用,并触发自定义警告。
步骤1:创建分析器项目
创建一个.NET Standard类库,安装以下NuGet包:
Microsoft.CodeAnalysis.AnalyzersMicrosoft.CodeAnalysis.CSharp
步骤2:编写分析器代码
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using System.Collections.Immutable; using System.Linq; [DiagnosticAnalyzer(LanguageNames.CSharp)] public class MyObsoleteAnalyzer : DiagnosticAnalyzer { // 自定义诊断ID,可自行修改 public const string DiagnosticId = "MYOBSOLETE001"; private const string Category = "Usage"; // 自定义警告消息 private const string WarningMessage = "This is a custom warning message"; private static readonly LocalizableString Title = "使用了过时成员"; private static readonly LocalizableString MessageFormat = "成员 '{0}' 已过时:" + WarningMessage; private static readonly LocalizableString Description = "访问了标记为MyObsolete的成员"; private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description); public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule); public override void Initialize(AnalysisContext context) { context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.EnableConcurrentExecution(); // 监听成员访问语法节点 context.RegisterSyntaxNodeAction(AnalyzeMemberAccess, SyntaxKind.SimpleMemberAccessExpression); } private void AnalyzeMemberAccess(SyntaxNodeAnalysisContext context) { var memberAccess = (MemberAccessExpressionSyntax)context.Node; var symbol = context.SemanticModel.GetSymbolInfo(memberAccess.Name).Symbol as IPropertySymbol; if (symbol == null) return; // 检查当前属性是否标记了MyObsoleteAttribute var hasMyObsoleteAttr = symbol.GetAttributes() .Any(attr => attr.AttributeClass?.Name == nameof(MyObsoleteAttribute)); if (hasMyObsoleteAttr) { // 触发警告 var diagnostic = Diagnostic.Create(Rule, memberAccess.Name.GetLocation(), symbol.Name); context.ReportDiagnostic(diagnostic); } } }
步骤3:使用分析器
将分析器项目引用到目标项目,或者打包成NuGet包安装。此后编译项目时,只要访问标记了MyObsolete的属性,就会触发自定义警告。
方案二:JetBrains Rider自定义配置(仅Rider生效)
如果仅在Rider环境下开发,可以直接通过IDE配置让MyObsoleteAttribute被识别为过时标记:
- 打开Rider设置(
Ctrl+Alt+S) - 导航到
Inspections > C# > Code style issues > Obsolete symbol usage - 在右侧面板找到Custom obsolete attributes,点击
Add - 输入
MyObsoleteAttribute的完整类型名(例如YourNamespace.MyObsoleteAttribute) - 在下方Message栏输入固定警告消息:
This is a custom warning message - 保存设置后,Rider会在使用标记了
MyObsolete的属性时,自动显示与原生Obsolete一致的警告提示。
内容的提问来源于stack exchange,提问作者Rowandish
相关产品推荐
相关产品推荐

