如何确保标记[AttributeUsage(AttributeTargets.Property)]的属性在类中仅修饰单个属性?
如何确保自定义属性在每个类的属性上最多使用一次?
可以实现,主要有编译时验证和运行时检查两种方案,其中编译时验证能在开发阶段提前发现问题,是更推荐的方式。
编译时验证(推荐)
通过Roslyn分析器在编译阶段做检查,直接在IDE或编译过程中报错,避免问题留到运行时。
实现思路
创建一个Roslyn分析器项目,遍历每个类的属性,统计被目标自定义属性标记的数量,一旦超过1就触发诊断提示。
简化示例代码
[DiagnosticAnalyzer(LanguageNames.CSharp)] public class SinglePropertyAttributeAnalyzer : DiagnosticAnalyzer { public const string DiagnosticId = "SinglePropertyAttribute"; private static readonly LocalizableString Title = "多个属性标记了[YourCustomAttribute]"; private static readonly LocalizableString MessageFormat = "类'{0}'中有{1}个属性标记了[YourCustomAttribute]; 最多允许一个"; private static readonly LocalizableString Description = "每个类最多只能有一个属性被[YourCustomAttribute]标记。"; private const string Category = "Usage"; private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Error, 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.RegisterSymbolAction(AnalyzeClass, SymbolKind.NamedType); } private void AnalyzeClass(SymbolAnalysisContext context) { var classSymbol = (INamedTypeSymbol)context.Symbol; if (classSymbol.TypeKind != TypeKind.Class) return; int attributeCount = 0; foreach (var property in classSymbol.GetMembers().OfType<IPropertySymbol>()) { if (property.GetAttributes().Any(attr => attr.AttributeClass?.Name == "YourCustomAttribute")) { attributeCount++; if (attributeCount > 1) { var diagnostic = Diagnostic.Create(Rule, property.Locations[0], classSymbol.Name, attributeCount); context.ReportDiagnostic(diagnostic); } } } } }
将YourCustomAttribute替换成你实际的自定义属性名称即可,这个分析器会在编译时拦截违规代码,直接给出错误提示。
运行时检查
如果不想开发Roslyn分析器,也可以通过反射在运行时做验证,比如在应用启动阶段扫描所有类。
实现示例
public static void ValidateSinglePropertyAttribute(Type type) { var markedProperties = type.GetProperties() .Where(p => p.GetCustomAttributes(typeof(YourCustomAttribute), inherit: false).Any()) .ToList(); if (markedProperties.Count > 1) { throw new InvalidOperationException($"类 {type.FullName} 中有 {markedProperties.Count} 个属性标记了[YourCustomAttribute]; 最多允许一个。"); } } // 应用启动时执行检查 foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { foreach (var type in assembly.GetTypes()) { ValidateSinglePropertyAttribute(type); } }
这种方式的缺点是问题只能在运行时暴露,适合小型项目或临时验证场景。
注意
AttributeUsage的AllowMultiple参数仅控制同一个属性上是否允许多次应用该自定义属性,无法限制同一个类中多个属性使用该属性,因此必须借助上述方案实现需求。
内容的提问来源于stack exchange,提问作者cogumel0
相关产品推荐
相关产品推荐

