[英]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.