{"id":332262,"date":"2022-04-22T03:00:12","date_gmt":"2022-04-22T03:00:12","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=332262"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=332262","title":{"rendered":"<span>\u0418\u0441\u0442\u043e\u0440\u0438\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u041d\u0415-\u041e\u0422\u0412\u0415\u0422\u0410 \u043d\u0430 stackoverflow<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/001\/b36\/9bf\/001b369bfea715c30b7e7ce8ab2079b2.png\" width=\"780\" height=\"440\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/001\/b36\/9bf\/001b369bfea715c30b7e7ce8ab2079b2.png\"\/><figcaption><\/figcaption><\/figure>\n<details class=\"spoiler\">\n<summary>\u041f\u0430\u0440\u0430 \u0441\u043b\u043e\u0432 \u043e \u041a\u0414\u041f\u0412<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0421\u043f\u0435\u0440\u0432\u0430 \u0445\u043e\u0442\u0435\u043b \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043c\u0435\u043c\u0438\u0447\u043d\u044b\u0439 \u043a\u0430\u0434\u0440 \u0441 \u043f\u043e\u0440\u0442\u0430\u043b\u043e\u043c \u0438\u0437 \u0420\u0438\u043a\u0430 \u0438 \u041c\u043e\u0440\u0442\u0438, \u043d\u043e \u043f\u043e\u0442\u043e\u043c \u0440\u0435\u0448\u0438\u043b, \u0447\u0442\u043e \u044d\u0442\u043e \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0438\u0437\u0431\u0438\u0442\u043e (\u043f\u043e\u043a\u0430 \u0441\u043e\u0431\u0438\u0440\u0430\u043b\u0441\u044f \u043f\u0438\u0441\u0430\u0442\u044c, \u0434\u0430\u0436\u0435 \u043a\u0442\u043e-\u0442\u043e \u0443\u0441\u043f\u0435\u043b \u0438\u043c \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f), \u043a \u0442\u043e\u043c\u0443 \u0436\u0435 \u0441\u0430\u043c \u043b\u0438\u0447\u043d\u043e \u043d\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u044d\u043f\u0438\u0437\u043e\u0434\u0430 \u043d\u0435 \u0432\u0438\u0434\u0435\u043b. \u0410 \u0432\u043e\u0442 \u043b\u044e\u0431\u0438\u043c\u0430\u044f \u043c\u043d\u043e\u0439 \u0441\u0435\u0440\u0438\u044f \u0438\u0433\u0440 Blackwell, \u043d\u0430\u043f\u0440\u043e\u0442\u0438\u0432, \u043d\u0435\u0437\u0430\u0441\u043b\u0443\u0436\u0435\u043d\u043d\u043e \u043e\u0431\u0434\u0435\u043b\u0435\u043d\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435\u043c.   <\/p>\n<\/div>\n<\/details>\n<p>\u041d\u0435\u0434\u0430\u0432\u043d\u043e \u043d\u0430\u0442\u043a\u043d\u0443\u043b\u0441\u044f \u043d\u0430 stackoverflow \u043d\u0430 \u0442\u0430\u043a\u043e\u0439 \u0432\u043e\u043f\u0440\u043e\u0441 <a href=\"https:\/\/stackoverflow.com\/questions\/71611998\/need-to-check-if-code-contains-certain-identifiers\" rel=\"noopener noreferrer nofollow\">Need to check if code contains certain identifiers<\/a> \u0438 \u0432 \u0445\u043e\u0434\u0435 \u0440\u0430\u0437\u043c\u044b\u0448\u043b\u0435\u043d\u0438\u0439 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0438\u043b\u0441\u044f \u0438\u0437 \u00ab\u043c\u0430\u043b\u0435\u043d\u044c\u043a\u043e\u0433\u043e \u043f\u043e\u043c\u043e\u0449\u043d\u0438\u043a\u0430 \u0421\u0430\u043d\u0442\u044b\u00bb \u0432 \u00ab\u0430\u0434\u0432\u043e\u043a\u0430\u0442\u0430 \u0434\u044c\u044f\u0432\u043e\u043b\u0430\u00bb. \u0427\u0442\u043e, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0432\u0435\u0441\u0435\u043b\u0435\u0435. \u041d\u043e \u043c\u043e\u0440\u0430\u043b\u044c \u043d\u0435 \u0432 \u044d\u0442\u043e\u043c.<\/p>\n<p>\u0421\u043c\u044b\u0441\u043b \u0432\u043e\u043f\u0440\u043e\u0441\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0447\u0435\u043b\u043e\u0432\u0435\u043a \u0445\u043e\u0447\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0437\u0430\u043f\u0440\u0435\u0449\u0451\u043d\u043d\u043e\u0433\u043e \u0435\u0433\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c\u0438 \u043a\u043e\u0434\u0430 \u0438 \u0432 \u044d\u0442\u043e\u043c \u043f\u0440\u043e\u0441\u0438\u0442 \u043f\u043e\u043c\u043e\u0449\u0438 \u0443 \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0430.<\/p>\n<details class=\"spoiler\">\n<summary>\u0412\u043e\u043f\u0440\u043e\u0441 (\u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b)<\/summary>\n<div class=\"spoiler__content\">\n<p><strong>Need to check if code contains certain identifiers<\/strong><\/p>\n<p>I am going to be dynamically compiling and executing code using Roslyn like the example below. I want to make sure the code does not violate some of my rules, like:<\/p>\n<ul>\n<li>\n<p>Does not use Reflection<\/p>\n<\/li>\n<li>\n<p>Does not use HttpClient or WebClient<\/p>\n<\/li>\n<li>\n<p>Does not use File or Directory classes in System.IO namespace<\/p>\n<\/li>\n<li>\n<p>Does not use Source Generators<\/p>\n<\/li>\n<li>\n<p>Does not call unmanaged code<\/p>\n<\/li>\n<\/ul>\n<p>Where in the following code would I insert my rules\/checks and how would I do them?<\/p>\n<pre><code class=\"cs\">using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Emit; using System.Reflection; using System.Runtime.CompilerServices;  string code = @\"using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.IO;  namespace Customization {     public class Script     {         public async Task&lt;object?> RunAsync(object? data)         {             \/\/The following should not be allowed             File.Delete(@\"\"C:\\Temp\\log.txt\"\");              return await Task.FromResult(data);         }     } }\";  var compilation = Compile(code); var bytes = Build(compilation);  Console.WriteLine(\"Done\");  CSharpCompilation Compile(string code) {     SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);      string? dotNetCoreDirectoryPath = Path.GetDirectoryName(typeof(object).GetTypeInfo().Assembly.Location);     if (String.IsNullOrWhiteSpace(dotNetCoreDirectoryPath))     {         throw new ArgumentNullException(\"Cannot determine path to current assembly.\");     }      string assemblyName = Path.GetRandomFileName();     List&lt;MetadataReference> references = new();     references.Add(MetadataReference.CreateFromFile(typeof(object).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Console).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Dictionary&lt;,>).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Task).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(Path.Combine(dotNetCoreDirectoryPath, \"System.Runtime.dll\")));      CSharpCompilation compilation = CSharpCompilation.Create(         assemblyName,         syntaxTrees: new[] { syntaxTree },         references: references,         options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));       SemanticModel model = compilation.GetSemanticModel(syntaxTree);     CompilationUnitSyntax root = (CompilationUnitSyntax)syntaxTree.GetRoot();      \/\/TODO: Check the code for use classes that are not allowed such as File in the System.IO namespace.     \/\/Not exactly sure how to walk through identifiers.     IEnumerable&lt;IdentifierNameSyntax> identifiers = root.DescendantNodes()         .Where(s => s is IdentifierNameSyntax)         .Cast&lt;IdentifierNameSyntax>();       return compilation; }  [MethodImpl(MethodImplOptions.NoInlining)] byte[] Build(CSharpCompilation compilation) {     using (MemoryStream ms = new())     {         \/\/Emit to catch build errors         EmitResult emitResult = compilation.Emit(ms);          if (!emitResult.Success)         {             Diagnostic? firstError =                 emitResult                     .Diagnostics                     .FirstOrDefault                     (                         diagnostic => diagnostic.IsWarningAsError ||                             diagnostic.Severity == DiagnosticSeverity.Error                     );              throw new Exception(firstError?.GetMessage());         }          return ms.ToArray();     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u0412\u043e\u043f\u0440\u043e\u0441 (\u043f\u0435\u0440\u0435\u0432\u043e\u0434)<\/summary>\n<div class=\"spoiler__content\">\n<p><strong>\u041d\u0430\u0434\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043b\u0438 \u043a\u043e\u0434 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b<\/strong><\/p>\n<p>\u042f \u0441\u043e\u0431\u0438\u0440\u0430\u044e\u0441\u044c \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043a\u043e\u0434 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c Roslyn, \u043a\u0430\u043a \u0432 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043d\u0438\u0436\u0435. \u0425\u043e\u0447\u0443 \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043a\u043e\u0434 \u043d\u0435 \u043d\u0430\u0440\u0443\u0448\u0430\u0435\u0442 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0437 \u043c\u043e\u0438\u0445 \u043f\u0440\u0430\u0432\u0438\u043b \u0432\u0440\u043e\u0434\u0435:<\/p>\n<ul>\n<li>\n<p>\u041d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u044e<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 HttpClient \u0438\u043b\u0438 WebClient<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043a\u043b\u0430\u0441\u0441\u044b File \u0438\u043b\u0438 Directory \u0438\u0437 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0430 \u0438\u043c\u0451\u043d System.IO<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u044b \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u043d\u0435\u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0439 \u043a\u043e\u0434<\/p>\n<\/li>\n<\/ul>\n<p>\u0413\u0434\u0435 \u0432 \u043d\u0438\u0436\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u043d\u043d\u043e\u043c \u043a\u043e\u0434\u0435 \u043c\u043d\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043c\u043e\u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u0430\/\u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438, \u0438 \u043a\u0430\u043a \u0438\u0445 \u0441\u0434\u0435\u043b\u0430\u0442\u044c?<\/p>\n<pre><code class=\"cs\">using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Emit; using System.Reflection; using System.Runtime.CompilerServices;  string code = @\"using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.IO;  namespace Customization {     public class Script     {         public async Task&lt;object?> RunAsync(object? data)         {             \/\/The following should not be allowed             File.Delete(@\"\"C:\\Temp\\log.txt\"\");              return await Task.FromResult(data);         }     } }\";  var compilation = Compile(code); var bytes = Build(compilation);  Console.WriteLine(\"Done\");  CSharpCompilation Compile(string code) {     SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);      string? dotNetCoreDirectoryPath = Path.GetDirectoryName(typeof(object).GetTypeInfo().Assembly.Location);     if (String.IsNullOrWhiteSpace(dotNetCoreDirectoryPath))     {         throw new ArgumentNullException(\"Cannot determine path to current assembly.\");     }      string assemblyName = Path.GetRandomFileName();     List&lt;MetadataReference> references = new();     references.Add(MetadataReference.CreateFromFile(typeof(object).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Console).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Dictionary&lt;,>).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Task).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(Path.Combine(dotNetCoreDirectoryPath, \"System.Runtime.dll\")));      CSharpCompilation compilation = CSharpCompilation.Create(         assemblyName,         syntaxTrees: new[] { syntaxTree },         references: references,         options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));       SemanticModel model = compilation.GetSemanticModel(syntaxTree);     CompilationUnitSyntax root = (CompilationUnitSyntax)syntaxTree.GetRoot();      \/\/TODO: Check the code for use classes that are not allowed such as File in the System.IO namespace.     \/\/Not exactly sure how to walk through identifiers.     IEnumerable&lt;IdentifierNameSyntax> identifiers = root.DescendantNodes()         .Where(s => s is IdentifierNameSyntax)         .Cast&lt;IdentifierNameSyntax>();       return compilation; }  [MethodImpl(MethodImplOptions.NoInlining)] byte[] Build(CSharpCompilation compilation) {     using (MemoryStream ms = new())     {         \/\/Emit to catch build errors         EmitResult emitResult = compilation.Emit(ms);          if (!emitResult.Success)         {             Diagnostic? firstError =                 emitResult                     .Diagnostics                     .FirstOrDefault                     (                         diagnostic => diagnostic.IsWarningAsError ||                             diagnostic.Severity == DiagnosticSeverity.Error                     );              throw new Exception(firstError?.GetMessage());         }          return ms.ToArray();     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041c\u0435\u043d\u044f \u044d\u0442\u043e \u0437\u0430\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430\u043b\u043e, \u0438, \u043d\u0430\u043a\u0438\u0434\u0430\u0432 \u0432 \u0433\u043e\u043b\u043e\u0432\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u0441\u043e\u0431\u0440\u0430\u043b\u0441\u044f \u044f \u0443\u0436\u0435, \u0431\u044b\u043b\u043e, \u043e\u0444\u043e\u0440\u043c\u043b\u044f\u0442\u044c \u043e\u0442\u0432\u0435\u0442, \u043a\u0430\u043a \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u043b \u043f\u043e\u0443\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0438\u0441\u0442\u043e\u0440\u0438\u044e \u0441 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u043f\u0440\u043e\u0448\u043b\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432. \u041d\u0430\u0448\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0430 \u043d\u0430\u0434 \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u044b\u043c \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u043e\u043c SQL \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043e\u0434\u043d\u043e\u0439 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e\u0439 ERP. \u041c\u044b \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u0437\u0430\u0449\u0438\u0442\u0443 \u043e\u0442 \u0438\u043d\u044a\u0435\u043a\u0446\u0438\u0439 \u0438 \u0431\u044b\u043b\u0438 \u0433\u043e\u0440\u0434\u044b \u0441\u043e\u0431\u043e\u0439, \u043d\u043e \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u0440\u0435\u0448\u0438\u043b\u043e \u043d\u0430 \u0432\u0441\u044f\u043a\u0438\u0439 \u0441\u043b\u0443\u0447\u0430\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043d\u0430\u0448\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u044e\u044e \u044d\u043a\u0441\u043f\u0435\u0440\u0442\u0438\u0437\u0443. \u0412 \u0438\u0442\u043e\u0433\u0435, \u044d\u043a\u0441\u043f\u0435\u0440\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u043b \u043d\u0430\u043c, \u043a\u0430\u043a \u0438\u0437 \u043d\u0430\u0448\u0435\u0439 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u043b\u0435\u0433\u043a\u043e \u0438 \u043d\u0435\u043f\u0440\u0438\u043d\u0443\u0436\u0434\u0451\u043d\u043d\u043e \u0438\u0437\u0432\u043b\u0435\u0447\u044c \u043b\u043e\u0433\u0438\u043d\u044b \u0441 \u0445\u0435\u0448\u0430\u043c\u0438 \u043f\u0430\u0440\u043e\u043b\u0435\u0439 \u0438 \u0435\u0449\u0435 \u0432\u0441\u044f\u043a\u0443\u044e \u043c\u0435\u043b\u043e\u0447\u044c. \u0412 \u043e\u0431\u0449\u0435\u043c, \u0440\u0435\u0437\u043e\u043d\u043d\u043e \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u0432, \u0447\u0442\u043e \u043b\u044e\u0431\u043e\u0439 \u043c\u043e\u0439 \u043e\u0442\u0432\u0435\u0442 \u0431\u0443\u0434\u0435\u0442 \u0434\u044b\u0440\u044f\u0432\u044b\u043c \u0438 \u043e\u0434\u043d\u0430\u0436\u0434\u044b \u043c\u043e\u0436\u0435\u0442 \u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043a\u043e\u0441\u0432\u0435\u043d\u043d\u043e\u0439 \u043f\u0440\u0438\u0447\u0438\u043d\u043e\u0439 \u0447\u044c\u0438\u0445-\u0442\u043e \u0444\u0438\u043d\u0430\u043d\u0441\u043e\u0432\u044b\u0445 \u0438 \u0440\u0435\u043f\u0443\u0442\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u043f\u043e\u0442\u0435\u0440\u044c, \u0440\u0435\u0448\u0438\u043b \u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u043f\u043e \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0443 \u00ab\u043d\u0435 \u043d\u0430\u0432\u0440\u0435\u0434\u0438\u00bb \u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u0442\u0430\u043b \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u044c \u0437\u0430 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u043e \u044d\u0442\u043e\u043c\u0443 \u0432\u043e\u043f\u0440\u043e\u0441\u0443. \u041a \u0441\u0447\u0430\u0441\u0442\u044c\u044e, \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u043e \u043d\u0430\u0448\u0435\u043b\u0441\u044f \u0431\u043e\u043b\u0435\u0435 \u043e\u0442\u0432\u0430\u0436\u043d\u044b\u0439 \u0438\u043d\u0436\u0435\u043d\u0435\u0440 \u0438 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0438\u043b \u0441\u0432\u043e\u044e \u0432\u0435\u0440\u0441\u0438\u044e, \u0430 \u0442\u0430\u043c \u0438 \u0441\u0430\u043c \u0430\u0432\u0442\u043e\u0440 \u043f\u043e\u0434\u0442\u044f\u043d\u0443\u043b\u0441\u044f.<\/p>\n<details class=\"spoiler\">\n<summary>\u041e\u0442\u0432\u0435\u0442 (\u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b)<\/summary>\n<div class=\"spoiler__content\">\n<p>When checking for the use of a particular class you can look for <code>IdentifierNameSyntax<\/code>\u00a0type nodes by using the\u00a0<code>OfType&lt;>()<\/code>\u00a0method and filter the results by class name:<\/p>\n<pre><code class=\"cs\">var names = root.DescendantNodes()     .OfType&lt;IdentifierNameSyntax>()     .Where(i => string.Equals(i.Identifier.ValueText, className, StringComparison.OrdinalIgnoreCase));<\/code><\/pre>\n<p>You can then use the\u00a0<code>SemanticModel<\/code>\u00a0to check the namespace of the class:<\/p>\n<pre><code class=\"cs\">foreach (var name in names) {     var typeInfo = model.GetTypeInfo(name);     if (string.Equals(typeInfo.Type?.ContainingNamespace?.ToString(), containingNamespace, StringComparison.OrdinalIgnoreCase))     {         throw new Exception($\"Class {containingNamespace}.{className} is not allowed.\");     } }<\/code><\/pre>\n<p>To check for the use of reflection or unmanaged code you could check for the relevant usings\u00a0<code>System.Reflection<\/code>\u00a0and\u00a0<code>System.Runtime.InteropServices<\/code>.<\/p>\n<pre><code class=\"cs\">if (root.Usings.Any(u => string.Equals(u.Name.ToString(), disallowedNamespace, StringComparison.OrdinalIgnoreCase))) {     throw new Exception($\"Namespace {disallowedNamespace} is not allowed.\"); }<\/code><\/pre>\n<p>This would catch cases where the usings were unused i.e., no actual reflection or unmanaged code, but that seems like an acceptable trade off.<\/p>\n<p>I&#8217;m not sure what to do about the source generator checks as these are normally included as project references so I don&#8217;t know how they&#8217;d run against dynamically compiled code.<\/p>\n<p>Keeping the checks in the same place and updating your code gives:<\/p>\n<pre><code class=\"cs\">namespace Customization {     public class Script     {         static readonly HttpClient client = new HttpClient();          public async Task&lt;object?> RunAsync(object? data)         {             \/\/The following should not be allowed             File.Delete(@\"\"C:\\Temp\\log.txt\"\");              return await Task.FromResult(data);         }     } }\";  var compilation = Compile(code);  var bytes = Build(compilation); Console.WriteLine(\"Done\");   CSharpCompilation Compile(string code) {     SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);      string? dotNetCoreDirectoryPath = Path.GetDirectoryName(typeof(object).GetTypeInfo().Assembly.Location);     if (String.IsNullOrWhiteSpace(dotNetCoreDirectoryPath))     {         throw new InvalidOperationException(\"Cannot determine path to current assembly.\");     }      string assemblyName = Path.GetRandomFileName();     List&lt;MetadataReference> references = new();     references.Add(MetadataReference.CreateFromFile(typeof(object).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Console).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Dictionary&lt;,>).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Task).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(HttpClient).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(Path.Combine(dotNetCoreDirectoryPath, \"System.Runtime.dll\")));      CSharpCompilation compilation = CSharpCompilation.Create(         assemblyName,         syntaxTrees: new[] { syntaxTree },         references: references,         options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));       SemanticModel model = compilation.GetSemanticModel(syntaxTree);     CompilationUnitSyntax root = (CompilationUnitSyntax)syntaxTree.GetRoot();      ThrowOnDisallowedClass(\"File\", \"System.IO\", root, model);     ThrowOnDisallowedClass(\"HttpClient\", \"System.Net.Http\", root, model);     ThrowOnDisallowedNamespace(\"System.Reflection\", root);     ThrowOnDisallowedNamespace(\"System.Runtime.InteropServices\", root);      return compilation; }  [MethodImpl(MethodImplOptions.NoInlining)] byte[] Build(CSharpCompilation compilation) {     using (MemoryStream ms = new())     {         \/\/Emit to catch build errors         EmitResult emitResult = compilation.Emit(ms);          if (!emitResult.Success)         {             Diagnostic? firstError =                 emitResult                     .Diagnostics                     .FirstOrDefault                     (                         diagnostic => diagnostic.IsWarningAsError ||                             diagnostic.Severity == DiagnosticSeverity.Error                     );              throw new Exception(firstError?.GetMessage());         }          return ms.ToArray();     } }  void ThrowOnDisallowedClass(string className, string containingNamespace, CompilationUnitSyntax root, SemanticModel model) {     var names = root.DescendantNodes()                     .OfType&lt;IdentifierNameSyntax>()                     .Where(i => string.Equals(i.Identifier.ValueText, className, StringComparison.OrdinalIgnoreCase));      foreach (var name in names)     {         var typeInfo = model.GetTypeInfo(name);         if (string.Equals(typeInfo.Type?.ContainingNamespace?.ToString(), containingNamespace, StringComparison.OrdinalIgnoreCase))         {             throw new Exception($\"Class {containingNamespace}.{className} is not allowed.\");         }     } }  void ThrowOnDisallowedNamespace(string disallowedNamespace, CompilationUnitSyntax root) {     if (root.Usings.Any(u => string.Equals(u.Name.ToString(), disallowedNamespace, StringComparison.OrdinalIgnoreCase)))     {         throw new Exception($\"Namespace {disallowedNamespace} is not allowed.\");     } }<\/code><\/pre>\n<p>I&#8217;ve used\u00a0<code>throw<\/code>\u00a0for rule violations here which will mean that multiple violations will not be reported all at once so you may want to tweak that so it&#8217;s a bit more efficient.<\/p>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u041e\u0442\u0432\u0435\u0442 (\u043f\u0435\u0440\u0435\u0432\u043e\u0434)<\/summary>\n<div class=\"spoiler__content\">\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u044f \u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430, \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u0438\u0441\u043a\u0430\u0442\u044c \u0443\u0437\u043b\u044b \u0442\u0438\u043f\u0430 <code>IdentifierNameSyntax<\/code>, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043c\u0435\u0442\u043e\u0434 <code>OfType&lt;>()<\/code>, \u0438 \u043e\u0442\u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043f\u043e \u0438\u043c\u0435\u043d\u0438 \u043a\u043b\u0430\u0441\u0441\u0430:<\/p>\n<pre><code class=\"cs\">var names = root.DescendantNodes()     .OfType&lt;IdentifierNameSyntax>()     .Where(i => string.Equals(i.Identifier.ValueText, className, StringComparison.OrdinalIgnoreCase));<\/code><\/pre>\n<p>\u0417\u0430\u0442\u0435\u043c \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>SemanticModel<\/code>\u00a0\u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0430 \u0438\u043c\u0451\u043d \u043a\u043b\u0430\u0441\u0441\u0430:<\/p>\n<pre><code class=\"cs\">foreach (var name in names) {     var typeInfo = model.GetTypeInfo(name);     if (string.Equals(typeInfo.Type?.ContainingNamespace?.ToString(), containingNamespace, StringComparison.OrdinalIgnoreCase))     {         throw new Exception($\"Class {containingNamespace}.{className} is not allowed.\");     } }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u0438 \u0438\u043b\u0438 \u043d\u0435\u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043d\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 using&#8217;\u0438 <code>System.Reflection<\/code>\u00a0\u0438<code>System.Runtime.InteropServices<\/code>.<\/p>\n<pre><code class=\"cs\">if (root.Usings.Any(u => string.Equals(u.Name.ToString(), disallowedNamespace, StringComparison.OrdinalIgnoreCase))) {     throw new Exception($\"Namespace {disallowedNamespace} is not allowed.\"); }<\/code><\/pre>\n<p>\u042d\u0442\u043e \u043e\u0442\u043b\u043e\u0432\u0438\u0442 \u0441\u043b\u0443\u0447\u0430\u0438, \u043a\u043e\u0433\u0434\u0430 using&#8217;\u0438 \u043d\u0435 \u0431\u044b\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u044b, \u0442.\u0435. \u0431\u0435\u0437 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0439 \u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u0438 \u0438\u043b\u0438 \u043d\u0435\u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u043e\u0433\u043e \u043a\u043e\u0434\u0430, \u043d\u043e \u044d\u0442\u043e \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043f\u0440\u0438\u0435\u043c\u043b\u0435\u043c\u044b\u043c \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0438\u0441\u0441\u043e\u043c.<\/p>\n<p>\u041d\u0435 \u0443\u0432\u0435\u0440\u0435\u043d, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0441 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430\u043c\u0438 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0430 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430, \u0442.\u043a. \u043e\u043d\u0438 \u043e\u0431\u044b\u0447\u043d\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u044e\u0442\u0441\u044f \u043a\u0430\u043a \u0441\u0441\u044b\u043b\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435 \u0437\u043d\u0430\u044e, \u043a\u0430\u043a \u043e\u043d\u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u044f\u0442\u0441\u044f \u0441 \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c.<\/p>\n<p>\u041e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0412\u0430\u0448\u0435\u0433\u043e \u043a\u043e\u0434\u0430 \u0434\u0430\u0451\u0442:<\/p>\n<pre><code class=\"cs\">namespace Customization {     public class Script     {         static readonly HttpClient client = new HttpClient();     public async Task&amp;lt;object?&amp;gt; RunAsync(object? data)     {         \/\/The following should not be allowed         File.Delete(@\"\"C:\\Temp\\log.txt\"\");          return await Task.FromResult(data);     } }  }\"; var compilation = Compile(code); var bytes = Build(compilation); Console.WriteLine(\"Done\"); CSharpCompilation Compile(string code) { SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code); string? dotNetCoreDirectoryPath = Path.GetDirectoryName(typeof(object).GetTypeInfo().Assembly.Location); if (String.IsNullOrWhiteSpace(dotNetCoreDirectoryPath)) {     throw new InvalidOperationException(\"Cannot determine path to current assembly.\"); }  string assemblyName = Path.GetRandomFileName(); List&amp;lt;MetadataReference&amp;gt; references = new(); references.Add(MetadataReference.CreateFromFile(typeof(object).Assembly.Location)); references.Add(MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location)); references.Add(MetadataReference.CreateFromFile(typeof(Console).Assembly.Location)); references.Add(MetadataReference.CreateFromFile(typeof(Dictionary&amp;lt;,&amp;gt;).Assembly.Location)); references.Add(MetadataReference.CreateFromFile(typeof(Task).Assembly.Location)); references.Add(MetadataReference.CreateFromFile(typeof(HttpClient).Assembly.Location)); references.Add(MetadataReference.CreateFromFile(Path.Combine(dotNetCoreDirectoryPath, \"System.Runtime.dll\")));  CSharpCompilation compilation = CSharpCompilation.Create(     assemblyName,     syntaxTrees: new[] { syntaxTree },     references: references,     options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));   SemanticModel model = compilation.GetSemanticModel(syntaxTree); CompilationUnitSyntax root = (CompilationUnitSyntax)syntaxTree.GetRoot();  ThrowOnDisallowedClass(\"File\", \"System.IO\", root, model); ThrowOnDisallowedClass(\"HttpClient\", \"System.Net.Http\", root, model); ThrowOnDisallowedNamespace(\"System.Reflection\", root); ThrowOnDisallowedNamespace(\"System.Runtime.InteropServices\", root);  return compilation;  } [MethodImpl(MethodImplOptions.NoInlining)] byte[] Build(CSharpCompilation compilation) { using (MemoryStream ms = new()) { \/\/Emit to catch build errors EmitResult emitResult = compilation.Emit(ms);     if (!emitResult.Success)     {         Diagnostic? firstError =             emitResult                 .Diagnostics                 .FirstOrDefault                 (                     diagnostic =&amp;gt; diagnostic.IsWarningAsError ||                         diagnostic.Severity == DiagnosticSeverity.Error                 );          throw new Exception(firstError?.GetMessage());     }      return ms.ToArray(); }  } void ThrowOnDisallowedClass(string className, string containingNamespace, CompilationUnitSyntax root, SemanticModel model) { var names = root.DescendantNodes() .OfType&lt;IdentifierNameSyntax>() .Where(i => string.Equals(i.Identifier.ValueText, className, StringComparison.OrdinalIgnoreCase)); foreach (var name in names) {     var typeInfo = model.GetTypeInfo(name);     if (string.Equals(typeInfo.Type?.ContainingNamespace?.ToString(), containingNamespace, StringComparison.OrdinalIgnoreCase))     {         throw new Exception($\"Class {containingNamespace}.{className} is not allowed.\");     } }  } void ThrowOnDisallowedNamespace(string disallowedNamespace, CompilationUnitSyntax root) { if (root.Usings.Any(u => string.Equals(u.Name.ToString(), disallowedNamespace, StringComparison.OrdinalIgnoreCase))) { throw new Exception($\"Namespace {disallowedNamespace} is not allowed.\"); } }<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u00a0<code>throw<\/code>\u00a0\u0434\u043b\u044f \u043d\u0430\u0440\u0443\u0448\u0435\u043d\u0438\u0439 \u043f\u0440\u0430\u0432\u0438\u043b, \u0447\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u043d\u0430\u0440\u0443\u0448\u0435\u043d\u0438\u044f \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u0430\u0445\u043e\u0442\u0435\u0442\u044c \u044d\u0442\u043e \u043f\u043e\u0434\u043f\u0440\u0430\u0432\u0438\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u0431\u044b\u043b\u043e \u0447\u0443\u0442\u044c \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u0435\u0435.<\/p>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043e\u0442\u0432\u0435\u0442 \u0430\u0432\u0442\u043e\u0440\u0430 \u0432\u043e\u043f\u0440\u043e\u0441\u0430 (\u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b)<\/summary>\n<div class=\"spoiler__content\">\n<p>The SymbolInfo class provides some of the meatadata needed to create rules to restrict use of certain code. Here is what I came up with so far. Any suggestions on how to improve on this would be appreciated.<\/p>\n<pre><code class=\"cs\">\/\/Check for banned namespaces string[] namespaceBlacklist = new string[] { \"System.Net\", \"System.IO\" };  foreach (IdentifierNameSyntax identifier in identifiers) {     SymbolInfo symbolInfo = semanticModel.GetSymbolInfo(identifier);      if (symbolInfo.Symbol is { })     {         if (symbolInfo.Symbol.Kind == SymbolKind.Namespace)         {             if (namespaceBlacklist.Any(ns => ns == symbolInfo.Symbol.ToDisplayString()))             {                 throw new Exception($\"Declaration of namespace '{symbolInfo.Symbol.ToDisplayString()}' is not allowed.\");             }         }         else if (symbolInfo.Symbol.Kind == SymbolKind.NamedType)         {             if (namespaceBlacklist.Any(ns => symbolInfo.Symbol.ToDisplayString().StartsWith(ns + \".\")))             {                 throw new Exception($\"Use of namespace '{identifier.Identifier.ValueText}' is not allowed.\");             }         }     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043e\u0442\u0432\u0435\u0442 \u0430\u0432\u0442\u043e\u0440\u0430 \u0432\u043e\u043f\u0440\u043e\u0441\u0430 (\u043f\u0435\u0440\u0435\u0432\u043e\u0434)<\/summary>\n<div class=\"spoiler__content\">\n<p>\u041a\u043b\u0430\u0441\u0441 SymbolInfo \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u0430\u0432\u0438\u043b \u0434\u043b\u044f \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430. \u0412\u043e\u0442 \u0447\u0442\u043e \u0443 \u043c\u0435\u043d\u044f \u043f\u043e\u043a\u0430 \u0432\u044b\u0448\u043b\u043e. \u0411\u0443\u0434\u0443 \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u0435\u043d \u0437\u0430 \u043b\u044e\u0431\u044b\u0435 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u043e \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044e.<\/p>\n<pre><code class=\"cs\">\/\/Check for banned namespaces string[] namespaceBlacklist = new string[] { \"System.Net\", \"System.IO\" };  foreach (IdentifierNameSyntax identifier in identifiers) {     SymbolInfo symbolInfo = semanticModel.GetSymbolInfo(identifier);      if (symbolInfo.Symbol is { })     {         if (symbolInfo.Symbol.Kind == SymbolKind.Namespace)         {             if (namespaceBlacklist.Any(ns => ns == symbolInfo.Symbol.ToDisplayString()))             {                 throw new Exception($\"Declaration of namespace '{symbolInfo.Symbol.ToDisplayString()}' is not allowed.\");             }         }         else if (symbolInfo.Symbol.Kind == SymbolKind.NamedType)         {             if (namespaceBlacklist.Any(ns => symbolInfo.Symbol.ToDisplayString().StartsWith(ns + \".\")))             {                 throw new Exception($\"Use of namespace '{identifier.Identifier.ValueText}' is not allowed.\");             }         }     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418 \u0442\u0443\u0442 \u0440\u043e\u043b\u044c \u043c\u0430\u043c\u043a\u0438\u043d\u043e\u0433\u043e \u0445\u0430\u043a\u0435\u0440\u0430 (\u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u044f \u043d\u0435 \u0433\u0440\u044d\u0439 \u0445\u044d\u0442 \u043a\u0430\u043a\u043e\u0439-\u043d\u0438\u0431\u0443\u0434\u044c, \u0430 \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0439 \u043c\u0438\u043c\u043e-\u043a\u0440\u043e\u043a\u043e\u0434\u0438\u043b, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0447\u0443\u0442\u043a\u0430 \u0448\u0430\u0440\u0438\u0442 \u0437\u0430 C#) \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0430\u0441\u044c \u043c\u043d\u0435 \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u0438\u0432\u043b\u0435\u043a\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0438, \u0447\u0442\u043e \u0432\u0430\u0436\u043d\u0435\u0435, \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0439.<\/p>\n<p>\u0418\u0442\u0430\u043a, \u0432 \u043f\u0443\u0442\u044c. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0431\u044b\u043b\u043e \u0431\u044b \u043d\u0435\u043f\u043b\u043e\u0445\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043e\u0434 \u0442\u0435\u0441\u0442\u043e\u043f\u0440\u0438\u0433\u043e\u0434\u043d\u044b\u043c. \u041d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043a\u043e\u0434\u0430 \u0438\u0437 \u0432\u043e\u043f\u0440\u043e\u0441\u0430 \u044f \u0441\u043e\u0437\u0434\u0430\u043b \u043a\u043b\u0430\u0441\u0441 <code>Compiler<\/code>, \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0432 \u0430\u0432\u0442\u043e\u0440\u0441\u043a\u0438\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438.<\/p>\n<details class=\"spoiler\">\n<summary>Compiler<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"cs\">using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Emit; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Threading.Tasks;  namespace UserCodeValidation {     public class Compiler     {         private readonly ICodeValidator validator;          public Compiler(ICodeValidator validator)         {             this.validator = validator;         }          public CSharpCompilation Compile(string code)         {             SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);              string? dotNetCoreDirectoryPath = Path.GetDirectoryName(typeof(object).GetTypeInfo().Assembly.Location);             if (String.IsNullOrWhiteSpace(dotNetCoreDirectoryPath))             {                 throw new ArgumentNullException(\"Cannot determine path to current assembly.\");             }              string assemblyName = Path.GetRandomFileName();             List&lt;MetadataReference> references = new();             references.Add(MetadataReference.CreateFromFile(typeof(object).Assembly.Location));             references.Add(MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location));             references.Add(MetadataReference.CreateFromFile(typeof(Console).Assembly.Location));             references.Add(MetadataReference.CreateFromFile(typeof(Dictionary&lt;,>).Assembly.Location));             references.Add(MetadataReference.CreateFromFile(typeof(Task).Assembly.Location));             references.Add(MetadataReference.CreateFromFile(Path.Combine(dotNetCoreDirectoryPath, \"System.Runtime.dll\")));              CSharpCompilation compilation = CSharpCompilation.Create(                 assemblyName,                 syntaxTrees: new[] { syntaxTree },                 references: references,                 options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));               SemanticModel model = compilation.GetSemanticModel(syntaxTree);             CompilationUnitSyntax root = (CompilationUnitSyntax)syntaxTree.GetRoot();              validator?.Validate(root, model);               return compilation;         }          [MethodImpl(MethodImplOptions.NoInlining)]         public byte[] Build(CSharpCompilation compilation)         {             using (MemoryStream ms = new())             {                 \/\/Emit to catch build errors                 EmitResult emitResult = compilation.Emit(ms);                  if (!emitResult.Success)                 {                     Diagnostic? firstError =                         emitResult                             .Diagnostics                             .FirstOrDefault                             (                                 diagnostic => diagnostic.IsWarningAsError ||                                     diagnostic.Severity == DiagnosticSeverity.Error                             );                      throw new Exception(firstError?.GetMessage());                 }                  return ms.ToArray();             }         }     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044e \u043a\u043e\u0434\u0430 \u0440\u0435\u0448\u0438\u043b \u0434\u0435\u043b\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 <code>ICodeValidator<\/code>, \u0437\u0430\u0434\u0430\u0432\u0430\u0435\u043c\u043e\u0433\u043e \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440.<\/p>\n<details class=\"spoiler\">\n<summary>ICodeValidator<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"cs\">using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax;  namespace UserCodeValidation {     public interface ICodeValidator     {         void Validate(CompilationUnitSyntax root, SemanticModel model);     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043e\u0442\u0432\u0435\u0442\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u043e\u0442\u0432\u0435\u0442\u0430 \u0430\u0432\u0442\u043e\u0440\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 <code>ICodeValidator<\/code>: <code>Answer<\/code> \u0438 <code>OwnAnswer<\/code> \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e. \u041a\u043e\u0434 \u0442\u043e\u0436\u0435 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u0438\u0431\u043b\u0438\u0436\u0435\u043d \u043a \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0430\u043c. \u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0432\u043c\u0435\u0441\u0442\u043e <code>Exception<\/code> \u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0431\u043e\u043b\u0435\u0435 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 <code>CodeValidationException<\/code>, \u0447\u0442\u043e\u0431\u044b \u0432 \u0442\u0435\u0441\u0442\u0430\u0445 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e \u0438\u0445 \u043d\u0430\u043b\u0438\u0447\u0438\u0435.<\/p>\n<details class=\"spoiler\">\n<summary>CodeValidationException<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"cs\">using System; using System.Runtime.Serialization;  namespace UserCodeValidation {     [Serializable]     public class CodeValidationException : Exception     {         public CodeValidationException(string message)             : base(message) { }          protected CodeValidationException(SerializationInfo info, StreamingContext context)             : base(info, context) { }     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>Answer<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"cs\">using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using System; using System.Linq;  namespace UserCodeValidation {     public class Answer : ICodeValidator     {         public void Validate(CompilationUnitSyntax root, SemanticModel model)         {             ThrowOnDisallowedClass(\"File\", \"System.IO\", root, model);             ThrowOnDisallowedClass(\"HttpClient\", \"System.Net.Http\", root, model);              ThrowOnDisallowedNamespace(\"System.Net\", root);             ThrowOnDisallowedNamespace(\"System.IO\", root);             ThrowOnDisallowedNamespace(\"System.Reflection\", root);             ThrowOnDisallowedNamespace(\"System.Runtime.InteropServices\", root);         }          void ThrowOnDisallowedClass(string className, string containingNamespace, CompilationUnitSyntax root, SemanticModel model)         {             var names = root.DescendantNodes()                             .OfType&lt;IdentifierNameSyntax>()                             .Where(i => string.Equals(i.Identifier.ValueText, className, StringComparison.OrdinalIgnoreCase));              foreach (var name in names)             {                 var typeInfo = model.GetTypeInfo(name);                 if (string.Equals(typeInfo.Type?.ContainingNamespace?.ToString(), containingNamespace, StringComparison.OrdinalIgnoreCase))                 {                     throw new CodeValidationException($\"Class {containingNamespace}.{className} is not allowed.\");                 }             }         }          void ThrowOnDisallowedNamespace(string disallowedNamespace, CompilationUnitSyntax root)         {             if (root.Usings.Any(u => string.Equals(u.Name.ToString(), disallowedNamespace, StringComparison.OrdinalIgnoreCase)))             {                 throw new CodeValidationException($\"Namespace {disallowedNamespace} is not allowed.\");             }         }     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>OwnAnswer<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"cs\">using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Collections.Generic; using System.Linq;  namespace UserCodeValidation {     public class OwnAnswer : ICodeValidator     {         public void Validate(CompilationUnitSyntax root, SemanticModel model)         {             IEnumerable&lt;IdentifierNameSyntax> identifiers = root.DescendantNodes()                 .Where(s => s is IdentifierNameSyntax)                 .Cast&lt;IdentifierNameSyntax>();             \/\/Check for banned namespaces             string[] namespaceBlacklist = new string[] { \"System.Net\", \"System.IO\", \"System.Reflection\", \"System.Runtime.InteropServices\" };             foreach (IdentifierNameSyntax identifier in identifiers)             {                 SymbolInfo symbolInfo = model.GetSymbolInfo(identifier);                  if (symbolInfo.Symbol is { })                 {                     if (symbolInfo.Symbol.Kind == SymbolKind.Namespace)                     {                         if (namespaceBlacklist.Any(ns => ns == symbolInfo.Symbol.ToDisplayString()))                         {                             throw new CodeValidationException($\"Declaration of namespace '{symbolInfo.Symbol.ToDisplayString()}' is not allowed.\");                         }                     }                     else if (symbolInfo.Symbol.Kind == SymbolKind.NamedType)                     {                         if (namespaceBlacklist.Any(ns => symbolInfo.Symbol.ToDisplayString().StartsWith(ns + \".\")))                         {                             throw new CodeValidationException($\"Use of namespace '{identifier.Identifier.ValueText}' is not allowed.\");                         }                     }                 }             }         }     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0438 \u0442\u0435\u0441\u0442\u044b \u043f\u0438\u0441\u0430\u0442\u044c. \u0414\u0430 \u043f\u0440\u043e\u0441\u0442\u044f\u0442 \u043c\u0435\u043d\u044f \u043f\u0443\u0440\u0438\u0441\u0442\u044b \u044e\u043d\u0438\u0442-\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043d\u043e \u0432\u0441\u0435 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438 \u0445\u043e\u0447\u0443 \u0438\u043c\u0435\u0442\u044c \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0442\u043e\u0434\u0435, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043d\u0430\u0431\u043e\u0440 \u0430\u0442\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432 <code>[InlineData]<\/code> \u0431\u0443\u0434\u0435\u0442 \u043a\u0430\u043a \u0431\u044b \u0441\u0432\u043e\u0434\u043d\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u0435\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432. \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0436\u0435 \u0431\u0443\u0434\u0443 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0438 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u043f\u044b\u0442\u043a\u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0444\u0430\u0439\u043b.<\/p>\n<details class=\"spoiler\">\n<summary>Tests<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"cs\">using System; using System.IO; using System.Reflection; using Xunit;  namespace UserCodeValidation.Tests {     public class Tests : IDisposable     {         #region Test data          private const string initialContents = \"initial contents\";          #endregion Test data          private readonly string file;          public Tests()         {             file = Path.GetRandomFileName();             File.WriteAllText(file, initialContents);         }          public void Dispose()         {             File.Delete(file);         }          [Theory]         public void Test(Type validator, string code, bool isValidCode, string finalContents = null)         {             \/\/ Arrange             code = code.Replace(\"&lt;file>\", file);             Compiler compiler = new Compiler((ICodeValidator)Activator.CreateInstance(validator));              \/\/ Act             Exception exception = Record.Exception(() =>             {                 Type script = Assembly.Load(compiler.Build(compiler.Compile(code))).GetType(\"Customization.Script\");                 script.GetMethod(\"RunAsync\").Invoke(Activator.CreateInstance(script), new object[] { default });             });              \/\/ Assert             Assert.Equal(isValidCode, exception is not CodeValidationException);             Assert.Equal(finalContents ?? initialContents, File.ReadAllText(file));         }     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0414\u043b\u044f \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442\u044c \u0443\u0441\u043f\u0435\u0448\u043d\u043e, \u0430 \u0444\u0430\u0439\u043b \u043e\u0441\u0442\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0435\u0438\u0437\u043c\u0435\u043d\u0435\u043d\u043d\u044b\u043c.<\/p>\n<pre><code class=\"cs\">private const string basicExample = @\" using System.Threading.Tasks;  namespace Customization {     public class Script     {         public async Task&lt;object?> RunAsync(object? data)         {             return await Task.FromResult(data);         }     } }\";<\/code><\/pre>\n<p>\u0422\u0435\u0441\u0442\u044b, \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e, \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0442.<\/p>\n<pre><code class=\"cs\">[Theory] [InlineData(typeof(Answer), basicExample, true)] [InlineData(typeof(OwnAnswer), basicExample, true)] public void Test(Type validator, string code, bool isValidCode, string finalContents = null) \/\/ ...<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043d\u0435\u043f\u0440\u0438\u043a\u0440\u044b\u0442\u044b\u0445 \u043f\u043e\u043f\u044b\u0442\u043e\u043a \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<pre><code class=\"cs\">private const string fullyQualifiedNameFileExample = @\" using System.Threading.Tasks;  namespace Customization {     public class Script     {         public async Task&lt;object?> RunAsync(object? data)         {             System.IO.File.Delete(\"\"&lt;file>\"\");              return await Task.FromResult(data);         }     } }\";  private const string namespaceFileExample = @\" using System.IO; using System.Threading.Tasks;  namespace Customization {     public class Script     {         public async Task&lt;object?> RunAsync(object? data)         {             File.Delete(\"\"&lt;file>\"\");              return await Task.FromResult(data);         }     } }\";<\/code><\/pre>\n<p>\u0432\u0430\u043b\u0438\u0434\u0430\u0442\u043e\u0440 \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0442\u044c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435, \u0441\u043f\u0430\u0441\u0430\u044f \u043d\u0435\u0441\u0447\u0430\u0441\u0442\u043d\u044b\u0439 \u0444\u0430\u0439\u043b. \u042d\u0442\u043e, \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0441\u043b\u0443\u0447\u0430\u0438, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0438 \u043f\u0438\u0441\u0430\u043b\u0441\u044f \u043a\u043e\u0434 \u0432 \u043e\u0442\u0432\u0435\u0442\u0430\u0445 \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441. \u0418 \u0442\u0430\u043a, \u043f\u043e \u0444\u0430\u043a\u0442\u0443, \u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442.<\/p>\n<pre><code class=\"cs\">[Theory] \/\/ ... [InlineData(typeof(Answer), fullyQualifiedNameFileExample, false)] [InlineData(typeof(OwnAnswer), fullyQualifiedNameFileExample, false)] [InlineData(typeof(Answer), namespaceFileExample, false)] [InlineData(typeof(OwnAnswer), namespaceFileExample, false)] public void Test(Type validator, string code, bool isValidCode, string finalContents = null) \/\/ ...<\/code><\/pre>\n<p>\u0410 \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0447\u043d\u0451\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0432\u0430\u043b\u0438\u0434\u0430\u0442\u043e\u0440\u044b \u043d\u0430 \u043f\u0440\u043e\u0447\u043d\u043e\u0441\u0442\u044c. \u0423\u0434\u0430\u0441\u0442\u0441\u044f \u043b\u0438 \u043e\u0431\u043c\u0430\u043d\u0443\u0442\u044c \u0438\u0445 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>using static<\/code>?<\/p>\n<pre><code class=\"cs\">private const string usingStaticExample = @\" using System.Threading.Tasks; using static System.IO.File;  namespace Customization {     public class Script     {         public async Task&lt;object?> RunAsync(object? data)         {             Delete(\"\"&lt;file>\"\");              return await Task.FromResult(data);         }     } }\";<\/code><\/pre>\n<p>\u041e\u0447\u0435\u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u043d\u0435\u0442.<\/p>\n<pre><code class=\"cs\">[Theory] \/\/ ... [InlineData(typeof(Answer), usingStaticExample, false)] [InlineData(typeof(OwnAnswer), usingStaticExample, false)] public void Test(Type validator, string code, bool isValidCode, string finalContents = null) \/\/ ...<\/code><\/pre>\n<p>\u0410 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0441\u0435\u0432\u0434\u043e\u043d\u0438\u043c\u043e\u0432 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432 \u0438\u043c\u0435\u043d \u0438 \u0442\u0438\u043f\u043e\u0432?<\/p>\n<pre><code class=\"cs\">private const string namespaceAliasExample = @\" using System.Threading.Tasks; using Alias = System.IO;  namespace Customization {     public class Script     {         public async Task&lt;object?> RunAsync(object? data)         {             Alias.File.Delete(\"\"&lt;file>\"\");              return await Task.FromResult(data);         }     } }\";  private const string typeAliasExample = @\" using System.Threading.Tasks; using Alias = System.IO.File;  namespace Customization {     public class Script     {         public async Task&lt;object?> RunAsync(object? data)         {             Alias.Delete(\"\"&lt;file>\"\");              return await Task.FromResult(data);         }     } }\";<\/code><\/pre>\n<p>\u0422\u043e\u0436\u0435 \u043d\u0435 \u043f\u0440\u043e\u043a\u0430\u0442\u0438\u043b\u043e.<\/p>\n<pre><code class=\"cs\">[Theory] \/\/ ... [InlineData(typeof(Answer), namespaceAliasExample, false)] [InlineData(typeof(OwnAnswer), namespaceAliasExample, false)] [InlineData(typeof(Answer), typeAliasExample, false)] [InlineData(typeof(OwnAnswer), typeAliasExample, false)] public void Test(Type validator, string code, bool isValidCode, string finalContents = null) \/\/ ...<\/code><\/pre>\n<p>\u0418\u043c \u043d\u0435 \u043d\u0440\u0430\u0432\u044f\u0442\u0441\u044f \u043f\u0441\u0435\u0432\u0434\u043e\u043d\u0438\u043c\u044b, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0435 <code>System.IO<\/code>. \u0410 \u0435\u0441\u043b\u0438 \u0442\u0430\u043a?<\/p>\n<pre><code class=\"cs\">private const string trickyAliasExample = @\" using System.Threading.Tasks; using Alias = System;  namespace Customization {     public class Script     {         public async Task&lt;object?> RunAsync(object? data)         {             Alias.IO.File.Delete(\"\"&lt;file>\"\");              return await Task.FromResult(data);         }     } }\";<\/code><\/pre>\n<p>\u042d\u0445&#8230; \u0410 \u043d\u0430\u0434\u0435\u0436\u0434\u044b \u0431\u044b\u043b\u0438&#8230;<\/p>\n<pre><code class=\"cs\">[Theory] \/\/ ... [InlineData(typeof(Answer), trickyAliasExample, false)] [InlineData(typeof(OwnAnswer), trickyAliasExample, false)] public void Test(Type validator, string code, bool isValidCode, string finalContents = null) \/\/ ...<\/code><\/pre>\n<p>\u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435, \u0432\u0441\u0435\u043c \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u043c \u0443\u0445\u0438\u0449\u0440\u0435\u043d\u0438\u044f\u043c \u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0441\u0442\u043e\u044f\u043b\u0430 \u043c\u043e\u0449\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a <code>Microsoft.CodeAnalysis.dll<\/code> \u0438 <code>Microsoft.CodeAnalysis.CSharp.dll<\/code> \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u0432\u0430\u043b\u0438\u0434\u0430\u0442\u043e\u0440\u043e\u0432, \u0438 \u043f\u043e\u043f\u044b\u0442\u043a\u0438 \u0431\u044b\u043b\u0438 \u0432\u0435\u0441\u044c\u043c\u0430 \u043d\u0430\u0438\u0432\u043d\u044b. \u0422\u0430\u043a \u0447\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043c\u0435\u043d\u044f\u0442\u044c \u043f\u043e\u0434\u0445\u043e\u0434. \u041d\u043e \u0441\u043f\u0435\u0440\u0432\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043e\u0442\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435.<\/p>\n<p>\u041a\u0430\u043a \u0432\u0430\u043b\u0438\u0434\u0430\u0442\u043e\u0440\u044b \u0441\u043f\u0440\u0430\u0432\u044f\u0442\u0441\u044f \u0441 \u0442\u0430\u043a\u0438\u043c\u0438 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f\u043c\u0438? \u0412 \u043d\u0438\u0445 \u0444\u0430\u0439\u043b \u043d\u0435 \u0443\u0434\u0430\u043b\u044f\u0435\u0442\u0441\u044f, \u043d\u043e \u0441\u0442\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435, \u0447\u0442\u043e \u0442\u043e\u0436\u0435 \u043d\u0435\u0436\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u043e.<\/p>\n<pre><code class=\"cs\">private const string fullyQualifiedNameStreamWriterExample = @\" using System.Threading.Tasks;  namespace Customization {     public class Script     {         public async Task&lt;object?> RunAsync(object? data)         {             using (new System.IO.StreamWriter(\"\"&lt;file>\"\")) ;              return await Task.FromResult(data);         }     } }\";  private const string namespaceStreamWriterExample = @\" using System.IO; using System.Threading.Tasks;  namespace Customization {     public class Script     {         public async Task&lt;object?> RunAsync(object? data)         {             using (new StreamWriter(\"\"&lt;file>\"\")) ;              return await Task.FromResult(data);         }     } }\";<\/code><\/pre>\n<p>\u041e\u0436\u0438\u0434\u0430\u0435\u043c\u043e, \u043e\u0434\u0438\u043d \u0442\u0435\u0441\u0442 \u0434\u043b\u044f <code>Answer<\/code> \u043f\u0430\u0434\u0430\u0435\u0442. \u041d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u043c\u043e\u0436\u0435\u043c \u0435\u043c\u0443, \u043e\u0431\u043d\u043e\u0432\u0438\u0432 \u043c\u0435\u0442\u043e\u0434 <code>Validate<\/code>. \u0412 \u043a\u043e\u043d\u0446\u0435 \u043a\u043e\u043d\u0446\u043e\u0432, \u043a\u043e\u043d\u0446\u0435\u043f\u0442\u0443\u0430\u043b\u044c\u043d\u043e \u044d\u0442\u043e \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043c\u0435\u043d\u044f\u0435\u0442.<\/p>\n<details class=\"spoiler\">\n<summary>Answer.Validate<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"cs\">public void Validate(CompilationUnitSyntax root, SemanticModel model) {     ThrowOnDisallowedClass(\"File\", \"System.IO\", root, model);     ThrowOnDisallowedClass(\"StreamWriter\", \"System.IO\", root, model); \/\/ update     ThrowOnDisallowedClass(\"HttpClient\", \"System.Net.Http\", root, model);      ThrowOnDisallowedNamespace(\"System.Net\", root);     ThrowOnDisallowedNamespace(\"System.IO\", root);     ThrowOnDisallowedNamespace(\"System.Reflection\", root);     ThrowOnDisallowedNamespace(\"System.Runtime.InteropServices\", root); }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u043f\u0435\u0440\u044c \u0443\u0436\u0435 \u044d\u0442\u043e\u0442 \u0442\u0435\u0441\u0442 \u043f\u0430\u0434\u0430\u0435\u0442 \u043d\u0435\u043e\u0436\u0438\u0434\u0430\u043d\u043d\u043e. \u041d\u043e \u0434\u0435\u0431\u0430\u0433 \u0432\u0441\u0451 \u0441\u0442\u0430\u0432\u0438\u0442 \u043d\u0430 \u0441\u0432\u043e\u0438 \u043c\u0435\u0441\u0442\u0430.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/24a\/224\/e7e\/24a224e7e148243cef9bf42d3e2864f3.png\" width=\"923\" height=\"242\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/24a\/224\/e7e\/24a224e7e148243cef9bf42d3e2864f3.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041c\u0435\u0442\u043e\u0434 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f<\/p>\n<pre><code class=\"cs\">TypeInfo GetTypeInfo(this SemanticModel semanticModel, SyntaxNode node, CancellationToken cancellationToken = default)<\/code><\/pre>\n<p>\u0434\u043b\u044f \u0442\u0430\u043a\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 \u043d\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0442\u0438\u043f (<code>ITypeSymbol<\/code>) \u0434\u043b\u044f \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 (<code>IdentifierNameSyntax<\/code>).<\/p>\n<p>\u0418\u0442\u0430\u043a, \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c:<\/p>\n<pre><code class=\"cs\">[Theory] \/\/ ... [InlineData(typeof(Answer), fullyQualifiedNameStreamWriterExample, true, \"\")] [InlineData(typeof(OwnAnswer), fullyQualifiedNameStreamWriterExample, false)] [InlineData(typeof(Answer), namespaceStreamWriterExample, false)] [InlineData(typeof(OwnAnswer), namespaceStreamWriterExample, false)] public void Test(Type validator, string code, bool isValidCode, string finalContents = null) \/\/ ...<\/code><\/pre>\n<p>\u0412\u0435\u0440\u043d\u0451\u043c\u0441\u044f \u043a \u043d\u0430\u0448\u0438\u043c \u0431\u0430\u0440\u0430\u043d\u0430\u043c. \u041e\u0434\u0438\u043d \u0438\u0437 \u0432\u0430\u043b\u0438\u0434\u0430\u0442\u043e\u0440\u043e\u0432 \u043f\u043e\u0432\u0435\u0440\u0436\u0435\u043d. \u041d\u043e, \u0432\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u044d\u0442\u043e \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e\u0441\u0442\u044c, \u044f \u0441\u0435\u0431\u0435  \u044d\u0442\u043e \u043d\u0435 \u0442\u0430\u043a \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u043b. \u0410, \u0432\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b, \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u0430. \u0422\u0430\u043a \u0447\u0442\u043e \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u043c. \u041a \u0447\u0435\u043c\u0443 \u0431\u044b\u043b\u043e \u043e\u0442\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435? \u0414\u043e \u043d\u0435\u0433\u043e \u0432\u0440\u0435\u0434\u043e\u043d\u043e\u0441\u043d\u044b\u0439 \u043a\u043e\u0434 \u0432\u044b\u0437\u044b\u0432\u0430\u043b\u0441\u044f \u0438\u0437 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430. \u041d\u043e \u0432\u0440\u0435\u0434\u0438\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u0438 \u0438\u0437 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u043d\u044b\u0445. \u0412 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u043e\u0432. \u0410 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u044b \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0435\u0440\u0435\u0437 <code>new()<\/code> \u0438 \u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u044e, \u043d\u043e \u0438 \u0447\u0435\u0440\u0435\u0437 <code>Activator<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0445\u043e\u0442\u044c \u0438 \u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u0440\u0443\u0435\u0442 \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c, \u043d\u043e \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0435 \u0438\u043c\u0451\u043d <code>System<\/code>. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043e\u0434\u0438\u043d \u0438\u0437 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432.<\/p>\n<pre><code class=\"cs\">private const string streamWriterViaActivatorExample = @\" using System; using System.Threading.Tasks;  namespace Customization {     public class Script     {         public async Task&lt;object?> RunAsync(object? data)         {             using ((IDisposable)Activator.CreateInstance(                 Type.GetType(\"\"System.IO.StreamWriter\"\"),                 new object[] { \"\"&lt;file>\"\" })) ;              return await Task.FromResult(data);         }     } }\";<\/code><\/pre>\n<p>\u041e\u0431\u0430 \u0432\u0430\u043b\u0438\u0434\u0430\u0442\u043e\u0440\u0430 \u043f\u0430\u043b\u0438.<\/p>\n<pre><code class=\"cs\">[Theory] \/\/ ... [InlineData(typeof(Answer), streamWriterViaActivatorExample, true, \"\")] [InlineData(typeof(OwnAnswer), streamWriterViaActivatorExample, true, \"\")] public void Test(Type validator, string code, bool isValidCode, string finalContents = null) \/\/ ...<\/code><\/pre>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0431\u043e\u043d\u0443\u0441\u0430 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0437\u0430\u0442\u0435\u0440\u0435\u0442\u044c \u0444\u0430\u0439\u043b, \u0430 \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0447\u0442\u043e-\u043d\u0438\u0431\u0443\u0434\u044c \u043e\u0441\u043c\u044b\u0441\u043b\u0435\u043d\u043d\u043e\u0435. \u041d\u043e <code>Activator<\/code> \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <code>object<\/code>, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043d\u0438\u0447\u0435\u0433\u043e \u043e\u0441\u043e\u0431\u043e \u043d\u0435 \u043f\u043e\u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0448\u044c. \u042f\u0432\u043d\u043e\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043d\u0435 \u043f\u0440\u043e\u0441\u043a\u043e\u0447\u0435\u0442 \u043c\u0438\u043c\u043e \u0432\u0430\u043b\u0438\u0434\u0430\u0442\u043e\u0440\u043e\u0432.<\/p>\n<pre><code class=\"cs\">private const string explicitCastExample = @\" using System; using System.Threading.Tasks;  namespace Customization {     public class Script     {         public async Task&lt;object?> RunAsync(object? data)         {             using (var sw = (System.IO.StreamWriter)Activator.CreateInstance(                 Type.GetType(\"\"System.IO.StreamWriter\"\"),                 new object[] { \"\"&lt;file>\"\" }))                 sw.Write(\"\"WASTED\"\");              return await Task.FromResult(data);         }     } }\";<\/code><\/pre>\n<pre><code class=\"cs\">[Theory] \/\/ ... [InlineData(typeof(Answer), explicitCastExample, false)] [InlineData(typeof(OwnAnswer), explicitCastExample, false)] public void Test(Type validator, string code, bool isValidCode, string finalContents = null) \/\/ ...<\/code><\/pre>\n<p>\u0410 <code>dynamic<\/code> \u043d\u0435 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0438\u0437-\u0437\u0430 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u044f \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 <code>Microsoft.CSharp.dll<\/code>. <\/p>\n<pre><code class=\"cs\">private const string dynamicExample = @\" using System; using System.Threading.Tasks;  namespace Customization {     public class Script     {         public async Task&lt;object?> RunAsync(object? data)         {             using (dynamic sw = (IDisposable)Activator.CreateInstance(                 Type.GetType(\"\"System.IO.StreamWriter\"\"),                 new object[] { \"\"&lt;file>\"\" }))                 sw.Write(\"\"WASTED\"\");              return await Task.FromResult(data);         }     } }\";<\/code><\/pre>\n<p>\u0425\u043e\u0442\u044f, \u0435\u0441\u043b\u0438 \u0430\u0432\u0442\u043e\u0440 \u0432\u043e\u043f\u0440\u043e\u0441\u0430 \u0437\u0430\u0445\u043e\u0447\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c <code>dynamic<\/code> (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 Excel) \u0438 \u043e\u0431\u043d\u043e\u0432\u0438\u0442 <code>Compiler.Compile<\/code>:<\/p>\n<details class=\"spoiler\">\n<summary>Compiler.Compile<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"cs\">public CSharpCompilation Compile(string code) {     SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);      string? dotNetCoreDirectoryPath = Path.GetDirectoryName(typeof(object).GetTypeInfo().Assembly.Location);     if (String.IsNullOrWhiteSpace(dotNetCoreDirectoryPath))     {         throw new ArgumentNullException(\"Cannot determine path to current assembly.\");     }      string assemblyName = Path.GetRandomFileName();     List&lt;MetadataReference> references = new();     references.Add(MetadataReference.CreateFromFile(typeof(object).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Console).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Dictionary&lt;,>).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Task).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo).Assembly.Location)); \/\/ enable `dynamic`     references.Add(MetadataReference.CreateFromFile(Path.Combine(dotNetCoreDirectoryPath, \"System.Runtime.dll\")));      CSharpCompilation compilation = CSharpCompilation.Create(         assemblyName,         syntaxTrees: new[] { syntaxTree },         references: references,         options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));       SemanticModel model = compilation.GetSemanticModel(syntaxTree);     CompilationUnitSyntax root = (CompilationUnitSyntax)syntaxTree.GetRoot();      validator?.Validate(root, model);       return compilation; }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u042d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0430\u0442\u043e\u0440\u0430\u043c \u043e\u0442\u043a\u0440\u043e\u0435\u0442\u0441\u044f \u0448\u0438\u0440\u043e\u043a\u0438\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0440 \u0434\u043b\u044f \u0442\u0432\u043e\u0440\u0447\u0435\u0441\u0442\u0432\u0430.<\/p>\n<pre><code class=\"cs\">[Theory] \/\/ ... [InlineData(typeof(Answer), dynamicExample, true, \"WASTED\")] [InlineData(typeof(OwnAnswer), dynamicExample, true, \"WASTED\")] public void Test(Type validator, string code, bool isValidCode, string finalContents = null) \/\/ ...<\/code><\/pre>\n<p>\u041d\u043e \u0447\u0442\u043e \u0436\u0435 \u0434\u0435\u043b\u0430\u0442\u044c, \u043f\u043e\u043a\u0430 \u044d\u0442\u043e\u0433\u043e \u043d\u0435 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e?.. \u0420\u0430\u0434\u043e\u0432\u0430\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u044d\u0442\u0438 \u0432\u0430\u043b\u0438\u0434\u0430\u0442\u043e\u0440\u044b \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u0431\u0435\u0437\u043f\u043e\u043b\u0435\u0437\u043d\u044b \u043f\u0440\u043e\u0442\u0438\u0432 \u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u0438 \u0447\u0443\u0442\u044c \u043c\u0435\u043d\u0435\u0435 \u0447\u0435\u043c \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e. \u041e\u043d\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0430 \u0438\u043c\u0451\u043d <code>System.Reflection<\/code>, \u0432\u044b\u0437\u043e\u0432 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u043d\u0430 \u0442\u0438\u043f\u0430\u0445 \u0438\u0437 \u043d\u0435\u0433\u043e \u0438 \u0432\u044b\u0437\u043e\u0432 \u043a\u043e\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u043e\u0432 \u044d\u0442\u0438\u0445 \u0442\u0438\u043f\u043e\u0432. \u0410 \u0435\u0441\u043b\u0438 \u043d\u0430 \u0442\u0438\u043f\u0435 \u0438\u0437 \u0440\u0430\u0437\u0440\u0435\u0448\u0451\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0430 \u0438\u043c\u0451\u043d \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0438\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0438\u0437 <code>System.Reflection<\/code>, \u0442\u043e \u0432\u0441\u0451 \u041e\u041a.<\/p>\n<pre><code class=\"cs\">private const string reflectionExample = @\" using System; using System.Threading.Tasks;  namespace Customization {     public class Script     {         public async Task&lt;object?> RunAsync(object? data)         {             var type = Type.GetType(\"\"System.IO.StreamWriter\"\");             using (var sw = (IDisposable) Activator.CreateInstance(type, new object[] { \"\"&lt;file>\"\" }))                 type.GetMethod(\"\"Write\"\", new[] { typeof(string) }).Invoke(sw, new object[] { \"\"WASTED\"\" });                          return await Task.FromResult(data);         }     } }\";<\/code><\/pre>\n<p>\u041e\u0431\u0430 \u0432\u0430\u043b\u0438\u0434\u0430\u0442\u043e\u0440\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0444\u0430\u0439\u043b\u0430.<\/p>\n<pre><code class=\"cs\">[Theory] \/\/ ... [InlineData(typeof(Answer), reflectionExample, true, \"WASTED\")] [InlineData(typeof(OwnAnswer), reflectionExample, true, \"WASTED\")] public void Test(Type validator, string code, bool isValidCode, string finalContents = null) \/\/ ...<\/code><\/pre>\n<p>\u0421\u0447\u0438\u0442\u0430\u044e \u0442\u0430\u043a\u043e\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043d\u0435\u043f\u043b\u043e\u0445\u0438\u043c \u0438 \u043d\u0430 \u044d\u0442\u043e\u043c, \u043f\u043e\u0436\u0430\u043b\u0443\u0439, \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u044e\u0441\u044c.<\/p>\n<hr\/>\n<p>\u0410\u0445, \u0434\u0430. \u041c\u043e\u0440\u0430\u043b\u044c, \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u0430\u044f \u0432\u043e \u0432\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0438. \u041d\u0430\u043a\u043e\u043b\u0435\u043d\u043d\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u043e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 &#8212; \u043a \u0431\u0435\u0434\u0435. \u0418\u043b\u0438 \u043d\u0435\u0441\u043a\u0443\u0447\u043d\u043e\u043c\u0443 \u0432\u0435\u0447\u0435\u0440\u0443. \u0421\u043c\u043e\u0442\u0440\u044f \u0441 \u043a\u0430\u043a\u043e\u0439 \u0412\u044b \u0441\u0442\u043e\u0440\u043e\u043d\u044b.<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"v-portal\" style=\"display:none;\"><\/div>\n<\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/662109\/\"> https:\/\/habr.com\/ru\/post\/662109\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<details class=\"spoiler\">\n<summary>\u041f\u0430\u0440\u0430 \u0441\u043b\u043e\u0432 \u043e \u041a\u0414\u041f\u0412<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0421\u043f\u0435\u0440\u0432\u0430 \u0445\u043e\u0442\u0435\u043b \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043c\u0435\u043c\u0438\u0447\u043d\u044b\u0439 \u043a\u0430\u0434\u0440 \u0441 \u043f\u043e\u0440\u0442\u0430\u043b\u043e\u043c \u0438\u0437 \u0420\u0438\u043a\u0430 \u0438 \u041c\u043e\u0440\u0442\u0438, \u043d\u043e \u043f\u043e\u0442\u043e\u043c \u0440\u0435\u0448\u0438\u043b, \u0447\u0442\u043e \u044d\u0442\u043e \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0438\u0437\u0431\u0438\u0442\u043e (\u043f\u043e\u043a\u0430 \u0441\u043e\u0431\u0438\u0440\u0430\u043b\u0441\u044f \u043f\u0438\u0441\u0430\u0442\u044c, \u0434\u0430\u0436\u0435 \u043a\u0442\u043e-\u0442\u043e \u0443\u0441\u043f\u0435\u043b \u0438\u043c \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f), \u043a \u0442\u043e\u043c\u0443 \u0436\u0435 \u0441\u0430\u043c \u043b\u0438\u0447\u043d\u043e \u043d\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u044d\u043f\u0438\u0437\u043e\u0434\u0430 \u043d\u0435 \u0432\u0438\u0434\u0435\u043b. \u0410 \u0432\u043e\u0442 \u043b\u044e\u0431\u0438\u043c\u0430\u044f \u043c\u043d\u043e\u0439 \u0441\u0435\u0440\u0438\u044f \u0438\u0433\u0440 Blackwell, \u043d\u0430\u043f\u0440\u043e\u0442\u0438\u0432, \u043d\u0435\u0437\u0430\u0441\u043b\u0443\u0436\u0435\u043d\u043d\u043e \u043e\u0431\u0434\u0435\u043b\u0435\u043d\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435\u043c.   <\/p>\n<\/div>\n<\/details>\n<p>\u041d\u0435\u0434\u0430\u0432\u043d\u043e \u043d\u0430\u0442\u043a\u043d\u0443\u043b\u0441\u044f \u043d\u0430 stackoverflow \u043d\u0430 \u0442\u0430\u043a\u043e\u0439 \u0432\u043e\u043f\u0440\u043e\u0441 <a href=\"https:\/\/stackoverflow.com\/questions\/71611998\/need-to-check-if-code-contains-certain-identifiers\" rel=\"noopener noreferrer nofollow\">Need to check if code contains certain identifiers<\/a> \u0438 \u0432 \u0445\u043e\u0434\u0435 \u0440\u0430\u0437\u043c\u044b\u0448\u043b\u0435\u043d\u0438\u0439 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0438\u043b\u0441\u044f \u0438\u0437 \u00ab\u043c\u0430\u043b\u0435\u043d\u044c\u043a\u043e\u0433\u043e \u043f\u043e\u043c\u043e\u0449\u043d\u0438\u043a\u0430 \u0421\u0430\u043d\u0442\u044b\u00bb \u0432 \u00ab\u0430\u0434\u0432\u043e\u043a\u0430\u0442\u0430 \u0434\u044c\u044f\u0432\u043e\u043b\u0430\u00bb. \u0427\u0442\u043e, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0432\u0435\u0441\u0435\u043b\u0435\u0435. \u041d\u043e \u043c\u043e\u0440\u0430\u043b\u044c \u043d\u0435 \u0432 \u044d\u0442\u043e\u043c.<\/p>\n<p>\u0421\u043c\u044b\u0441\u043b \u0432\u043e\u043f\u0440\u043e\u0441\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0447\u0435\u043b\u043e\u0432\u0435\u043a \u0445\u043e\u0447\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0437\u0430\u043f\u0440\u0435\u0449\u0451\u043d\u043d\u043e\u0433\u043e \u0435\u0433\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c\u0438 \u043a\u043e\u0434\u0430 \u0438 \u0432 \u044d\u0442\u043e\u043c \u043f\u0440\u043e\u0441\u0438\u0442 \u043f\u043e\u043c\u043e\u0449\u0438 \u0443 \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0430.<\/p>\n<details class=\"spoiler\">\n<summary>\u0412\u043e\u043f\u0440\u043e\u0441 (\u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b)<\/summary>\n<div class=\"spoiler__content\">\n<p><strong>Need to check if code contains certain identifiers<\/strong><\/p>\n<p>I am going to be dynamically compiling and executing code using Roslyn like the example below. I want to make sure the code does not violate some of my rules, like:<\/p>\n<ul>\n<li>\n<p>Does not use Reflection<\/p>\n<\/li>\n<li>\n<p>Does not use HttpClient or WebClient<\/p>\n<\/li>\n<li>\n<p>Does not use File or Directory classes in System.IO namespace<\/p>\n<\/li>\n<li>\n<p>Does not use Source Generators<\/p>\n<\/li>\n<li>\n<p>Does not call unmanaged code<\/p>\n<\/li>\n<\/ul>\n<p>Where in the following code would I insert my rules\/checks and how would I do them?<\/p>\n<pre><code class=\"cs\">using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Emit; using System.Reflection; using System.Runtime.CompilerServices;  string code = @\"using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.IO;  namespace Customization {     public class Script     {         public async Task&lt;object?> RunAsync(object? data)         {             \/\/The following should not be allowed             File.Delete(@\"\"C:\\Temp\\log.txt\"\");              return await Task.FromResult(data);         }     } }\";  var compilation = Compile(code); var bytes = Build(compilation);  Console.WriteLine(\"Done\");  CSharpCompilation Compile(string code) {     SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);      string? dotNetCoreDirectoryPath = Path.GetDirectoryName(typeof(object).GetTypeInfo().Assembly.Location);     if (String.IsNullOrWhiteSpace(dotNetCoreDirectoryPath))     {         throw new ArgumentNullException(\"Cannot determine path to current assembly.\");     }      string assemblyName = Path.GetRandomFileName();     List&lt;MetadataReference> references = new();     references.Add(MetadataReference.CreateFromFile(typeof(object).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Console).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Dictionary&lt;,>).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Task).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(Path.Combine(dotNetCoreDirectoryPath, \"System.Runtime.dll\")));      CSharpCompilation compilation = CSharpCompilation.Create(         assemblyName,         syntaxTrees: new[] { syntaxTree },         references: references,         options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));       SemanticModel model = compilation.GetSemanticModel(syntaxTree);     CompilationUnitSyntax root = (CompilationUnitSyntax)syntaxTree.GetRoot();      \/\/TODO: Check the code for use classes that are not allowed such as File in the System.IO namespace.     \/\/Not exactly sure how to walk through identifiers.     IEnumerable&lt;IdentifierNameSyntax> identifiers = root.DescendantNodes()         .Where(s => s is IdentifierNameSyntax)         .Cast&lt;IdentifierNameSyntax>();       return compilation; }  [MethodImpl(MethodImplOptions.NoInlining)] byte[] Build(CSharpCompilation compilation) {     using (MemoryStream ms = new())     {         \/\/Emit to catch build errors         EmitResult emitResult = compilation.Emit(ms);          if (!emitResult.Success)         {             Diagnostic? firstError =                 emitResult                     .Diagnostics                     .FirstOrDefault                     (                         diagnostic => diagnostic.IsWarningAsError ||                             diagnostic.Severity == DiagnosticSeverity.Error                     );              throw new Exception(firstError?.GetMessage());         }          return ms.ToArray();     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u0412\u043e\u043f\u0440\u043e\u0441 (\u043f\u0435\u0440\u0435\u0432\u043e\u0434)<\/summary>\n<div class=\"spoiler__content\">\n<p><strong>\u041d\u0430\u0434\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043b\u0438 \u043a\u043e\u0434 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b<\/strong><\/p>\n<p>\u042f \u0441\u043e\u0431\u0438\u0440\u0430\u044e\u0441\u044c \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043a\u043e\u0434 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c Roslyn, \u043a\u0430\u043a \u0432 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043d\u0438\u0436\u0435. \u0425\u043e\u0447\u0443 \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043a\u043e\u0434 \u043d\u0435 \u043d\u0430\u0440\u0443\u0448\u0430\u0435\u0442 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0437 \u043c\u043e\u0438\u0445 \u043f\u0440\u0430\u0432\u0438\u043b \u0432\u0440\u043e\u0434\u0435:<\/p>\n<ul>\n<li>\n<p>\u041d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u044e<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 HttpClient \u0438\u043b\u0438 WebClient<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043a\u043b\u0430\u0441\u0441\u044b File \u0438\u043b\u0438 Directory \u0438\u0437 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0430 \u0438\u043c\u0451\u043d System.IO<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u044b \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u043d\u0435\u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0439 \u043a\u043e\u0434<\/p>\n<\/li>\n<\/ul>\n<p>\u0413\u0434\u0435 \u0432 \u043d\u0438\u0436\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u043d\u043d\u043e\u043c \u043a\u043e\u0434\u0435 \u043c\u043d\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043c\u043e\u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u0430\/\u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438, \u0438 \u043a\u0430\u043a \u0438\u0445 \u0441\u0434\u0435\u043b\u0430\u0442\u044c?<\/p>\n<pre><code class=\"cs\">using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Emit; using System.Reflection; using System.Runtime.CompilerServices;  string code = @\"using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.IO;  namespace Customization {     public class Script     {         public async Task&lt;object?> RunAsync(object? data)         {             \/\/The following should not be allowed             File.Delete(@\"\"C:\\Temp\\log.txt\"\");              return await Task.FromResult(data);         }     } }\";  var compilation = Compile(code); var bytes = Build(compilation);  Console.WriteLine(\"Done\");  CSharpCompilation Compile(string code) {     SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);      string? dotNetCoreDirectoryPath = Path.GetDirectoryName(typeof(object).GetTypeInfo().Assembly.Location);     if (String.IsNullOrWhiteSpace(dotNetCoreDirectoryPath))     {         throw new ArgumentNullException(\"Cannot determine path to current assembly.\");     }      string assemblyName = Path.GetRandomFileName();     List&lt;MetadataReference> references = new();     references.Add(MetadataReference.CreateFromFile(typeof(object).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Console).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Dictionary&lt;,>).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(typeof(Task).Assembly.Location));     references.Add(MetadataReference.CreateFromFile(Path.Combine(dotNetCoreDirectoryPath, \"System.Runtime.dll\")));      CSharpCompilation compilation = CSharpCompilation.Create(         assemblyName,         syntaxTrees: new[] { syntaxTree },         references: references,         options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));       SemanticModel model = compilation.GetSemanticModel(syntaxTree);     CompilationUnitSyntax root = (CompilationUnitSyntax)syntaxTree.GetRoot();      \/\/TODO: Check the code for use classes that are not allowed such as File in the System.IO namespace.     \/\/Not exactly sure how to walk through identifiers.     IEnumerable&lt;IdentifierNameSyntax> identifiers = root.DescendantNodes()         .Where(s => s is IdentifierNameSyntax)         .Cast&lt;IdentifierNameSyntax>();       return compilation; }  [MethodImpl(MethodImplOptions.NoInlining)] byte[] Build(CSharpCompilation compilation) {     using (MemoryStream ms = new())     {         \/\/Emit to catch build errors         EmitResult emitResult = compilation.Emit(ms);          if (!emitResult.Success)         {             Diagnostic? firstError =                 emitResult                     .Diagnostics                     .FirstOrDefault                     (                         diagnostic => diagnostic.IsWarningAsError ||                             diagnostic.Severity == DiagnosticSeverity.Error                     );              throw new Exception(firstError?.GetMessage());         }          return ms.ToArray();     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041c\u0435\u043d\u044f \u044d\u0442\u043e \u0437\u0430\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430\u043b\u043e, \u0438, \u043d\u0430\u043a\u0438\u0434\u0430\u0432 \u0432 \u0433\u043e\u043b\u043e\u0432\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u0441\u043e\u0431\u0440\u0430\u043b\u0441\u044f \u044f \u0443\u0436\u0435, \u0431\u044b\u043b\u043e, \u043e\u0444\u043e\u0440\u043c\u043b\u044f\u0442\u044c \u043e\u0442\u0432\u0435\u0442, \u043a\u0430\u043a \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u043b \u043f\u043e\u0443\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0438\u0441\u0442\u043e\u0440\u0438\u044e \u0441 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u043f\u0440\u043e\u0448\u043b\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432. \u041d\u0430\u0448\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0430 \u043d\u0430\u0434 \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u044b\u043c \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u043e\u043c SQL \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043e\u0434\u043d\u043e\u0439 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e\u0439 ERP. \u041c\u044b \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u0437\u0430\u0449\u0438\u0442\u0443 \u043e\u0442 \u0438\u043d\u044a\u0435\u043a\u0446\u0438\u0439 \u0438 \u0431\u044b\u043b\u0438 \u0433\u043e\u0440\u0434\u044b \u0441\u043e\u0431\u043e\u0439, \u043d\u043e \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u0440\u0435\u0448\u0438\u043b\u043e \u043d\u0430 \u0432\u0441\u044f\u043a\u0438\u0439 \u0441\u043b\u0443\u0447\u0430\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043d\u0430\u0448\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u044e\u044e \u044d\u043a\u0441\u043f\u0435\u0440\u0442\u0438\u0437\u0443. \u0412 \u0438\u0442\u043e\u0433\u0435, \u044d\u043a\u0441\u043f\u0435\u0440\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u043b \u043d\u0430\u043c, \u043a\u0430\u043a \u0438\u0437 \u043d\u0430\u0448\u0435\u0439 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u043b\u0435\u0433\u043a\u043e \u0438 \u043d\u0435\u043f\u0440\u0438\u043d\u0443\u0436\u0434\u0451\u043d\u043d\u043e \u0438\u0437\u0432\u043b\u0435\u0447\u044c \u043b\u043e\u0433\u0438\u043d\u044b \u0441 \u0445\u0435\u0448\u0430\u043c\u0438 \u043f\u0430\u0440\u043e\u043b\u0435\u0439 \u0438 \u0435\u0449\u0435 \u0432\u0441\u044f\u043a\u0443\u044e \u043c\u0435\u043b\u043e\u0447\u044c. \u0412 \u043e\u0431\u0449\u0435\u043c, \u0440\u0435\u0437\u043e\u043d\u043d\u043e \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u0432, \u0447\u0442\u043e \u043b\u044e\u0431\u043e\u0439 \u043c\u043e\u0439 \u043e\u0442\u0432\u0435\u0442 \u0431\u0443\u0434\u0435\u0442 \u0434\u044b\u0440\u044f\u0432\u044b\u043c \u0438 \u043e\u0434\u043d\u0430\u0436\u0434\u044b \u043c\u043e\u0436\u0435\u0442 \u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043a\u043e\u0441\u0432\u0435\u043d\u043d\u043e\u0439 \u043f\u0440\u0438\u0447\u0438\u043d\u043e\u0439 \u0447\u044c\u0438\u0445-\u0442\u043e \u0444\u0438\u043d\u0430\u043d\u0441\u043e\u0432\u044b\u0445 \u0438 \u0440\u0435\u043f\u0443\u0442\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u043f\u043e\u0442\u0435\u0440\u044c, \u0440\u0435\u0448\u0438\u043b \u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u043f\u043e \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0443 \u00ab\u043d\u0435 \u043d\u0430\u0432\u0440\u0435\u0434\u0438\u00bb \u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u0442\u0430\u043b \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u044c \u0437\u0430 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u043e \u044d\u0442\u043e\u043c\u0443 \u0432\u043e\u043f\u0440\u043e\u0441\u0443. \u041a \u0441\u0447\u0430\u0441\u0442\u044c\u044e, \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u043e \u043d\u0430\u0448\u0435\u043b\u0441\u044f \u0431\u043e\u043b\u0435\u0435 \u043e\u0442\u0432\u0430\u0436\u043d\u044b\u0439 \u0438\u043d\u0436\u0435\u043d\u0435\u0440 \u0438 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0438\u043b \u0441\u0432\u043e\u044e \u0432\u0435\u0440\u0441\u0438\u044e, \u0430 \u0442\u0430\u043c \u0438 \u0441\u0430\u043c \u0430\u0432\u0442\u043e\u0440 \u043f\u043e\u0434\u0442\u044f\u043d\u0443\u043b\u0441\u044f.<\/p>\n<details class=\"spoiler\">\n<summary>\u041e\u0442\u0432\u0435\u0442 (\u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b)<\/summary>\n<div class=\"spoiler__content\">\n<p>When checking for the use of a particular class you can look for <code>IdentifierNameSyntax<\/code>\u00a0type nodes by using the\u00a0<code>OfType&lt;>()<\/code>\u00a0method and filter the results by class name:<\/p>\n<pre><code class=\"cs\">var names = root.DescendantNodes()     .OfType&lt;IdentifierNameSyntax>()     .Where(i => string.Equals(i.Identifier.ValueText, className, StringComparison.OrdinalIgnoreCase));<\/code><\/pre>\n<p>You can then use the\u00a0<code>SemanticModel<\/code>\u00a0to check the namespace of the class:<\/p>\n<pre><code class=\"cs\">foreach (var name in names) {     var typeInfo = model.GetTypeInfo(name);     if (string.Equals(typeInfo.Type?.ContainingNamespace?.ToString(), containingNamespace, StringComparison.OrdinalIgnoreCase))     {         throw new Exception($\"Class {containingNamespace}.{className} is not allowed.\");     } }<\/code><\/pre>\n<p>To check for the use of reflection or unmanaged code you could check for the relevant usings\u00a0<code>System.Reflection<\/code>\u00a0and\u00a0<code>System.Runtime.InteropServices<\/code>.<\/p>\n<pre><code class=\"cs\">if (root.Usings.Any(u => string.Equals(u.Name.ToString(), disallowedNamespace,<\/code><\/pre>\n<\/div>\n<\/details>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-332262","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/332262","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=332262"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/332262\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=332262"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=332262"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=332262"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}