You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#代码中编写编译器指令?能否自定义编译校验属性?

Can I create custom compile-time checks like [Obsolete]?

Absolutely! This kind of custom compile-time enforcement is totally achievable in .NET, and the tool you’ll want to use is Roslyn Analyzers—the same underlying technology that makes built-in attributes like [Obsolete] trigger compiler errors or warnings.

How it works

The [Obsolete] attribute is recognized natively by the C#/VB compilers, but for your specific requirement (enforcing that classes marked with [ControllingAttribute] have at least one method with [NecessaryMethod]), you’ll build a custom analyzer that runs during compilation to validate this rule.

Step-by-step implementation

Here’s a high-level breakdown of how to build this:

  1. Define your custom attributes
    First, create the two attributes you mentioned—these are just regular .NET attributes, no special compiler hooks needed yet:

    [AttributeUsage(AttributeTargets.Class, Inherited = false)]
    public class ControllingAttribute : Attribute { }
    
    [AttributeUsage(AttributeTargets.Method)]
    public class NecessaryMethodAttribute : Attribute { }
    
  2. Create a Roslyn Analyzer project
    In Visual Studio, you can use the "Analyzer with Code Fix (.NET Standard)" template to start. This project will contain your analysis logic.

  3. Write the analysis logic
    Your analyzer will:

    • Scan all classes in the codebase
    • Check if a class has the [ControllingAttribute] applied
    • For those classes, verify if at least one method has the [NecessaryMethodAttribute]
    • If no such method exists, report a compiler error (which will block compilation, just like [Obsolete("", true)])

    Here’s a simplified snippet of the analyzer logic:

    [DiagnosticAnalyzer(LanguageNames.CSharp)]
    public class ControllingClassAnalyzer : DiagnosticAnalyzer
    {
        public const string DiagnosticId = "ControllingClass_RequiresNecessaryMethod";
    
        private static readonly LocalizableString Title = "Class requires a necessary method";
        private static readonly LocalizableString MessageFormat = "Class '{0}' is marked with [ControllingAttribute] but has no methods marked with [NecessaryMethod]";
        private static readonly LocalizableString Description = "Classes marked with [ControllingAttribute] must contain at least one method marked with [NecessaryMethod].";
        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(AnalyzeSymbol, SymbolKind.NamedType);
        }
    
        private void AnalyzeSymbol(SymbolAnalysisContext context)
        {
            var namedTypeSymbol = (INamedTypeSymbol)context.Symbol;
            // Check if the class has ControllingAttribute
            if (!namedTypeSymbol.GetAttributes().Any(attr => attr.AttributeClass.Name == nameof(ControllingAttribute)))
                return;
    
            // Check if any method has NecessaryMethodAttribute
            var hasNecessaryMethod = namedTypeSymbol.GetMembers()
                .OfType<IMethodSymbol>()
                .Any(method => method.GetAttributes().Any(attr => attr.AttributeClass.Name == nameof(NecessaryMethodAttribute)));
    
            if (!hasNecessaryMethod)
            {
                var diagnostic = Diagnostic.Create(Rule, namedTypeSymbol.Locations[0], namedTypeSymbol.Name);
                context.ReportDiagnostic(diagnostic);
            }
        }
    }
    
  4. Test and deploy

    • Use the included unit test project to verify your analyzer works as expected (e.g., flag invalid classes, pass valid ones)
    • Package the analyzer into a NuGet package, then reference it in your target projects. Once referenced, the compiler will run your analyzer during every build and block compilation if the rule is violated.

Alternatives (for older frameworks)

If you’re working with .NET Framework (pre-.NET Core/.NET 5+), you could also use FxCop (or legacy Code Analysis) to create similar rules, but Roslyn Analyzers are the modern, cross-platform recommended approach—they integrate directly with the compiler and work in all modern .NET environments.

内容的提问来源于stack exchange,提问作者IgorZhurbenko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 17:17:47