繁体   English   中英

仅允许为特定类扩展类 - c#

[英]Allowing extending classes only for specific classes - c#

是否可以只允许特定的类来扩展 class?

Suppose I have created class A but I want to allow to inherit this class only for class B and class C. 表示 class A 不应允许扩展 class。

是否可以在 c# 中以这种方式实现? 使用反射或任何其他方式?

您只能通过在不同程序集中定义其他类并将基础 class 的构造函数声明为internal来做到这一点。

可以在基本类型的构造函数中检查this.GetType() (记住: GetType()返回具体类型),如果它不是“批准的类型”,则抛出。但是,这是运行时检查之外的类型系统。

protected BaseTypeCtor() {
  if (GetType() != typeof(OnlyAllowedSubtype))
    throw new Exception("Nope! Not allowed to subclass this type!");
}

可见性限制——可能导致编译时错误——通常只能在程序集级别或所有子类型中控制。

如果类型确实在不同的程序集中,则将基本构造函数标记为internal可能就足够了,而且通常更干净。 不幸的是,C# 目前无法指定“内部受保护”作为修饰符。

如果您想在编译时执行此操作,但不想使用internal修饰符(例如,如果这是在包中),您可以做的是创建自己的 Roslyn 分析器。

这是一个非常基本的示例,说明如何针对编译时错误实现此目的:

[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class PreventInheritanceAnalyzer : DiagnosticAnalyzer
{
    public const string DiagnosticId = "PreventInheritanceAnalyzer";

    private static readonly string Title = "Title";
    private static readonly string MessageFormat = "Message format";
    private static readonly string Description = "Description";
    private const string Category = "Naming";
    private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category,
        DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description);
    private static HashSet<string> _acceptedClasses;

    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);

    public PreventInheritanceAnalyzer()
    {
        _acceptedClasses = new HashSet<string>(new[] { "MyNumberOneClass", "MyOtherSpecialClass" });
    }

    public override void Initialize(AnalysisContext context)
    {
        context.EnableConcurrentExecution();
        context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
        context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.NamedType);
    }

    private static void AnalyzeSymbol(SymbolAnalysisContext context)
    {
        var namedTypeSymbol = (INamedTypeSymbol)context.Symbol;

        // if it's not a class, we are not interested
        if (namedTypeSymbol.TypeKind != TypeKind.Class)
        {
            return;
        }

        // if it doesn't inherit from our special class, we are not interested,
        // and if it does but its name is one we allow, we are still not interested
        if (namedTypeSymbol.BaseType == null || namedTypeSymbol.BaseType.Name != "MySpecialClass" || _acceptedClasses.Contains(namedTypeSymbol.Name))
        {
            return;
        }

        // otherwise, this is a bad class, report the error
        var diagnostic = Diagnostic.Create(Rule, namedTypeSymbol.Locations[0], namedTypeSymbol.Name);
        context.ReportDiagnostic(diagnostic);
    }
}

这是一个非常基本的单元测试,以证明上述工作:

[TestMethod]
public void TestMethod2()
{
    var test = @"
        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
        using System.Threading.Tasks;
        using System.Diagnostics;

        namespace ConsoleApplication1
        {
            public class MySpecialClass { }
            public class MyNumberOneClass : MySpecialClass { }
            public class MySuperSpecialClass : MySpecialClass { }
        }";

    VerifyCSharpDiagnostic(test, new[]
    {
        new DiagnosticResult
        {
            Id = "PreventInheritanceAnalyzer",
            Locations = new[] { new DiagnosticResultLocation("Test0.cs", 13, 18) },
            Message = "Message format",
            Severity = DiagnosticSeverity.Error
        }
    });
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM