如何检查C#文件使用的类与方法?如何安全扫描插件代码限制API调用?
针对你的两个C#相关问题,我来分享下实际开发中常用的解决方案,都是经过项目验证的靠谱方法:
最靠谱的方式是利用微软官方的Roslyn编译器服务,它能直接解析C#源码的语法树和语义信息,精准识别类、方法的引用,比正则表达式或者简单字符串匹配靠谱得多。
Roslyn语法/语义分析实现
你可以通过编写代码遍历源码的语法节点,或者借助SemanticModel获取符号的具体类型信息,区分定义和引用,还能处理using别名、泛型等复杂场景:// 示例代码:解析C#文件并输出所有引用的类和方法 var sourceCode = File.ReadAllText("TargetFile.cs"); var syntaxTree = CSharpSyntaxTree.ParseText(sourceCode); // 创建临时编译上下文,添加必要的程序集引用 var compilation = CSharpCompilation.Create("TempAnalysisCompilation") .AddReferences(MetadataReference.CreateFromFile(typeof(object).Assembly.Location)) .AddSyntaxTrees(syntaxTree); var semanticModel = compilation.GetSemanticModel(syntaxTree); // 遍历所有标识符节点,获取对应的符号信息 var identifierNodes = syntaxTree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>(); foreach (var node in identifierNodes) { var symbol = semanticModel.GetSymbolInfo(node).Symbol; if (symbol != null) { var fullName = symbol.ContainingType != null ? $"{symbol.ContainingType.FullName}.{symbol.Name}" : symbol.Name; Console.WriteLine($"引用的类/方法:{fullName}"); } }快速轻量方案
如果只是临时手动查看,也可以用VS的「查找所有引用」功能,或者Resharper这类工具的代码分析功能,但如果需要自动化批量处理,Roslyn是首选。
这个需求属于插件安全管控的范畴,建议结合Roslyn白名单检查+运行时权限隔离的双重方案,既能在编译前拦截危险代码,又能在运行时做兜底防护。
编译前的Roslyn白名单扫描
先定义好允许调用的类型/方法白名单(比如你的API、Math类),然后通过Roslyn的语义分析遍历源码中的所有符号引用,检查是否在白名单内:// 示例:检查代码是否引用了禁止的类型/方法 var allowedFullNames = new HashSet<string> { "System.Math", "YourPluginApiNamespace.CoreApi", "YourPluginApiNamespace.Utils" }; var forbiddenFullNames = new HashSet<string> { "System.IO.File", "System.IO.StreamWriter", "System.Net.WebClient" }; foreach (var node in identifierNodes) { var symbol = semanticModel.GetSymbolInfo(node).Symbol; if (symbol?.ContainingType != null) { var typeFullName = symbol.ContainingType.FullName; if (forbiddenFullNames.Contains(typeFullName)) { throw new InvalidOperationException($"代码中引用了禁止的类型:{typeFullName}"); } if (!allowedFullNames.Contains(typeFullName) && !typeFullName.StartsWith("System.")) { // 这里可以根据需求调整:比如允许部分基础System类,或者严格只放行白名单 throw new InvalidOperationException($"代码中引用了未授权的类型:{typeFullName}"); } } }语义分析能准确识别类型的真实全名,避免开发者通过using别名或者命名空间嵌套绕过检查。
运行时的权限隔离
即使做了编译前扫描,也建议在加载插件时用AppDomain或者AssemblyLoadContext设置严格的权限,作为兜底:// 示例:创建受限的AppDomain,禁止文件IO等危险操作 var permissionSet = new PermissionSet(PermissionState.None); // 只允许执行权限 permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution)); // 允许有限的反射权限(按需调整) permissionSet.AddPermission(new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess)); var domainSetup = new AppDomainSetup { ApplicationBase = AppDomain.CurrentDomain.BaseDirectory }; var pluginDomain = AppDomain.CreateDomain("RestrictedPluginDomain", null, domainSetup, permissionSet); // 从该AppDomain加载插件程序集 var pluginAssembly = pluginDomain.Load("PluginAssemblyName");进阶方案:自定义Roslyn分析器
如果需要更复杂的规则(比如禁止特定方法、检查参数合法性),可以创建自定义的Roslyn分析器,将检查逻辑集成到编译流程中,编译时直接抛出错误提示,比手动遍历更高效,也更易于维护。
内容的提问来源于stack exchange,提问作者R1PFake

