本文为大家带来 Laugh 的“主程必杀技”系列文章第四篇《Unity C# 自动化执行代码规范-检查继承关系》。更多技术分享,请访问 Laugh 的 Unity 官方开发者社区主页,持续关注学习。
演示代码
获取链接:https://gitee.com/palang/unity-sharp-code-regulator.git
⦁ 检查继承关系
Unity C# 自动化执行代码规范
检查继承关系
实现目标
为了实现自己控制的帧驱动逻辑,我在项目定义了 IFrameDrivable 接口(其中有OnFrameUpdate 等方法,不是这里的重点,可以忽略)。
我希望实现 IFrameDrivable 的类,不能继承自 MonoBehaviour 类。
编写 Analyzer 分析器
首先在类 DianogsticIDs 中定义新的错误 ID:
public const string FORCE_NAMING_CONVENTIONS_ID= "FERR1004";
定义分析器类
新建分析器类 ForbidInheritFromMonoBehavor.cs,内容如下(具体步骤请看代码中的注释)
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis;
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.Immutable;
using Analyzer;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Linq;
namespace CdeAnalyzer
{
/**
* Author: Laugh(笑微)
* https://developer.unity.cn/projects/65937455edbc2a001cbd8102
*/
[ ]
internal class ForbidInheritFromMonoBehavor : DiagnosticAnalyzer
{
/// <summary>
/// 错误描述
/// </summary>
private static readonly DiagnosticDescriptor ForbidInheritDescriptor =
new DiagnosticDescriptor(
DianogsticIDs.FORCE_FORBID_INHERIT_MONOBEHAVIOR_ID, // ID
"实现了IFrameDrivable接口的类,不能继承自MonoBehavior", // Title
"实现了IFrameDrivable接口的类,不能继承自MonoBehavior", // Message format
DiagnosticCategories.Criterion, // Category
DiagnosticSeverity.Error, // Severity
isEnabledByDefault: true // Enabled by default
);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(ForbidInheritDescriptor);
/// <summary>
/// 初始化分析方法
/// </summary>
/// <param name="context"></param>
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxTreeAction(AnalyzeSymbol);
}
/// <summary>
/// 检测方法
/// </summary>
/// <param name="context"></param>
private static void AnalyzeSymbol(SyntaxTreeAnalysisContext context)
{
//找到文档的语法根树
var root = context.Tree.GetRoot(context.CancellationToken);
if (ConstraintDefinition.ExcludeAnalize(context.Tree.FilePath))
{//排除特殊目录
return;
}
var classList = root.DescendantNodes()?.OfType<ClassDeclarationSyntax>();
foreach(var cls in classList)
{//遍历语法树中的所有类
var baseClsList = cls.BaseList?.ChildNodes()?.OfType<SimpleBaseTypeSyntax>();
if (baseClsList == null)
{
break;
}
bool isMonoBehavior = false;
bool isFrameDrivable = false;
foreach (var bcls in baseClsList)
{
var idName = bcls.ChildNodes()?.OfType<IdentifierNameSyntax>()?.First();
var bname = idName.ToString();
if(bname == "IFrameDrivable")
{//检查是否实现了接口IFrameDrivable
isFrameDrivable = true;
}
else if (bname == "ArrayList")
{//检查是否继承自MonoBehavior
isMonoBehavior = true;
}
}
if (isFrameDrivable && isMonoBehavior)
{
//报错
var diagnostic = Diagnostic.Create(ForbidInheritDescriptor, cls.GetFirstToken().GetLocation());
context.ReportDiagnostic(diagnostic);
}
}
}
}
}