



{"id":2238,"date":"2025-04-21T17:44:53","date_gmt":"2025-04-21T17:44:53","guid":{"rendered":"https:\/\/www.w3computing.com\/articles\/?p=2238"},"modified":"2025-04-21T17:44:59","modified_gmt":"2025-04-21T17:44:59","slug":"file-scoped-types-csharp-12-cleaner-namespaces-safer-encapsulation","status":"publish","type":"post","link":"https:\/\/www.w3computing.com\/articles\/file-scoped-types-csharp-12-cleaner-namespaces-safer-encapsulation\/","title":{"rendered":"File-Scoped Types in C# 12: Cleaner Namespaces, Safer Encapsulation"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">C# has evolved significantly over the years, and each version brings new features aimed at improving readability, maintainability, and developer productivity. With C# 12, one of the more subtle but powerful additions is <strong>File-Scoped Types<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now, if you&#8217;re just hearing about this for the first time, you might be wondering: \u201cFile-scoped what now? Aren\u2019t types always file-scoped unless they\u2019re in a nested namespace?\u201d<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Fair question.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s break down what File-Scoped Types really are, why they matter, how they change the way we think about type visibility and encapsulation in C#, and how you can start using them effectively today.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">What Are File-Scoped Types?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In C# 12, <strong>file-scoped types<\/strong> refer to a new kind of type visibility\u2014types that are <strong>visible only within the file in which they are declared<\/strong>, even if they\u2019re declared as <code>class<\/code>, <code>struct<\/code>, or <code>interface<\/code> without using the <code>private<\/code> or <code>internal<\/code> modifier.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This might sound familiar if you\u2019ve worked with top-level statements in C# 9 or file-scoped namespaces in C# 10. The idea is the same: reduce boilerplate, enhance encapsulation, and keep things tidy at the file level.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But there\u2019s a twist.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Previously, if you wanted a type to be invisible outside of a file, you\u2019d use <code>internal<\/code> or <code>private<\/code> in some cases. But this wasn&#8217;t always semantically or practically clean. <code>internal<\/code> still exposed the type to the entire assembly. <code>private<\/code> could only be used in nested type definitions. There was no native way to say:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">&#8220;Hey compiler, this type should only be visible inside this one file. Period.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Until now.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">With C# 12\u2019s <strong><code>file<\/code> modifier<\/strong>, we get exactly that.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Syntax<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Here\u2019s how you declare a file-scoped type:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">file <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">MyPrivateHelper<\/span>\n{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">DoSomethingInternal<\/span>(<span class=\"hljs-params\"><\/span>)<\/span>\n    {\n        Console.WriteLine(<span class=\"hljs-string\">\"Doing something that's nobody else's business.\"<\/span>);\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">In this example, <code>MyPrivateHelper<\/code> can <strong>only be used within the same file<\/strong>. Not in other classes. Not in other files in the same namespace. Not in the same assembly. Just this one file.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Why Use File-Scoped Types?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This is where things get interesting. Why would you want to do this? What\u2019s the point?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s look at a few very practical reasons:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1. Better Encapsulation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">One of the core principles of good software design is encapsulation: hiding unnecessary details from the outside world. You already do this by making methods and fields <code>private<\/code>, right?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now imagine you have a helper class, a builder, or a small data container type that\u2019s only used by one class. Maybe it\u2019s even only used by a single method, but it\u2019s big enough to warrant its own type.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Before C# 12, your only options were:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Nest it inside another class (which makes the outer class bigger).<\/li>\n\n\n\n<li>Mark it <code>internal<\/code> and define it in the same namespace, which makes it visible to the whole assembly.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Both approaches have drawbacks. File-scoped types give you a <strong>third option<\/strong>: write that helper as a regular class in the same file, without polluting the assembly with types that nobody else should be using.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2. Cleaner Namespaces<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">We\u2019ve all had that experience: autocomplete in Visual Studio shows a dozen types you didn\u2019t even know existed, because someone defined a bunch of internal classes that are now visible across the project.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">File-scoped types reduce namespace pollution. They\u2019re not just <code>internal<\/code>, they\u2019re invisible.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3. Faster Code Navigation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If a type is file-scoped, you immediately know that its usage is tightly coupled to the file you\u2019re looking at. This helps you navigate and reason about code faster.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4. Better Separation of Concerns<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of cramming all logic into a single class or nesting types awkwardly, file-scoped types encourage cleaner separation without sacrificing encapsulation.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">File-Scoped Types vs Other Access Modifiers<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s compare file-scoped types to other access modifiers:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Modifier<\/th><th>Scope<\/th><th>Can Be Applied to Top-Level Types?<\/th><th>Use Case<\/th><\/tr><\/thead><tbody><tr><td><code>public<\/code><\/td><td>Everywhere<\/td><td>Yes<\/td><td>For shared types used across projects<\/td><\/tr><tr><td><code>internal<\/code><\/td><td>Within same assembly<\/td><td>Yes<\/td><td>Shared within the project<\/td><\/tr><tr><td><code>protected<\/code><\/td><td>Derived classes<\/td><td>No (only for class members)<\/td><td>For inheritance-related visibility<\/td><\/tr><tr><td><code>private<\/code><\/td><td>Declaring class only<\/td><td>No (only for nested types\/members)<\/td><td>Tightest control within a class<\/td><\/tr><tr><td><code>file<\/code><\/td><td>Current file only<\/td><td><strong>Yes (new in C# 12)<\/strong><\/td><td>Helper types used in only one file<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">So the <code>file<\/code> modifier fills a very specific, previously unaddressed niche.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">A Practical Example<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s look at a realistic scenario.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Suppose you have a file <code>OrderProcessor.cs<\/code>, and you\u2019re building logic to process customer orders. You might need a validator, or a parser, or maybe a DTO-like helper structure\u2014but it\u2019s only used internally in this file.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Before C# 12<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">internal<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">OrderValidator<\/span>\n{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">bool<\/span> <span class=\"hljs-title\">IsValid<\/span>(<span class=\"hljs-params\">Order order<\/span>)<\/span> =&gt; order.Quantity &gt; <span class=\"hljs-number\">0<\/span>;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Even though you marked it as <code>internal<\/code>, any other file in the project could still use <code>OrderValidator<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">With File-Scoped Types (C# 12)<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">file <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">OrderValidator<\/span>\n{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">bool<\/span> <span class=\"hljs-title\">IsValid<\/span>(<span class=\"hljs-params\">Order order<\/span>)<\/span> =&gt; order.Quantity &gt; <span class=\"hljs-number\">0<\/span>;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Now, the compiler enforces a strict boundary: <code>OrderValidator<\/code> can\u2019t be used outside this file. That\u2019s a cleaner contract.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Real-World Use Cases<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s talk scenarios. Here\u2019s when file-scoped types really shine:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1. Helper Classes for a Specific Class<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s say you have a <code>ReportGenerator<\/code> class, and you need a <code>ReportFormatter<\/code>. If the formatter is only used within <code>ReportGenerator.cs<\/code>, make it a file-scoped type.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2. One-Off Types for Parsing\/Processing<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Temporary parsers, tokenizers, or small state machine implementations that support a single feature are great candidates.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3. Private Data Shapes for Serialization<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Sometimes you shape data specifically for a file\u2019s needs\u2014say, a model that mimics a JSON payload but doesn\u2019t map directly to your domain model. Don\u2019t leak it into the global scope.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4. Testing Utilities<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If you have mock implementations or stubs used only in a test file, make them file-scoped to avoid accidental reuse across other tests.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">A Deep Dive Into the Compiler Behavior<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">So, what happens under the hood when you use <code>file<\/code>?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">C# compilers treat <code>file<\/code> as a unique access modifier. When compiling, the compiler ensures:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Type name collisions are allowed<\/strong> across files, since the type is invisible outside.<\/li>\n\n\n\n<li><strong>Other files cannot reference or use the file-scoped type<\/strong>, even if they\u2019re in the same namespace or assembly.<\/li>\n\n\n\n<li><strong>No metadata exposure<\/strong>: the type doesn\u2019t appear in compiled DLL\u2019s public or internal API surface.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">This makes <code>file<\/code> the most restrictive access level for top-level types.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But beware\u2014<strong>if you use partial classes<\/strong>, file-scoped types <strong>cannot<\/strong> participate across multiple files. They\u2019re truly scoped to a single file.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Tips for Using File-Scoped Types Effectively<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Here are some guidelines for getting the most out of file-scoped types:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u2705 Use When a Type Is Tightly Coupled to File Logic<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If your type is only used to support logic in one file, it\u2019s a great candidate.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u2705 Use Instead of Nesting If Nesting Gets Too Messy<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Nesting types just to hide them can reduce readability. File-scoped types offer an alternative that doesn\u2019t clutter your outer class.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u2705 Pair with File-Scoped Namespaces<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Using C# 10\u2019s file-scoped namespaces and C# 12\u2019s file-scoped types together can create a beautiful, minimal structure.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">namespace<\/span> <span class=\"hljs-title\">MyApp.Processing<\/span>;\n\nfile <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Tokenizer<\/span> { ... }\nfile <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Lexer<\/span> { ... }\n\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Processor<\/span> { ... }<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">\u274c Don\u2019t Use for Types That May Need Reuse<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Once a type is marked <code>file<\/code>, you can&#8217;t use it elsewhere. That\u2019s the point. If there\u2019s even a slight chance it\u2019ll be shared later, consider <code>internal<\/code> or <code>private<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u274c Don\u2019t Overuse It<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Not everything needs to be hidden. Use this for truly private or one-off types, not just to \u201ctidy things up.\u201d<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Tooling and IDE Support<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">As of Visual Studio 2022 (and newer versions), file-scoped types are fully supported. IntelliSense respects the scope, syntax highlighting works, and you\u2019ll get compile-time errors if you try to reference file-scoped types across files.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you use Roslyn analyzers or ReSharper, you may also start seeing recommendations to use file-scoped types when applicable.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Migrating Existing Code<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Now you might be thinking: should I go back and refactor my entire codebase?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Probably not. But as you touch files during regular development, keep an eye out for types that:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Are defined only to support logic in one file<\/li>\n\n\n\n<li>Are marked <code>internal<\/code> but not reused elsewhere<\/li>\n\n\n\n<li>Could benefit from tighter visibility<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Then you can confidently refactor them to be <code>file<\/code>-scoped.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Limitations and Gotchas<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Like any new feature, file-scoped types have limitations you need to be aware of:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1. No Cross-File <code>partial<\/code> Support<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">You can\u2019t split a file-scoped type into multiple files. If you try, the compiler will complain.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2. No Assembly Exposure<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This is by design, but it also means you\u2019ll need to rename the type or move it if you suddenly need broader visibility.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3. Incompatible with Older C# Versions<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Trying to use <code>file<\/code> in a C# 11 or earlier project will result in errors. Make sure your project targets C# 12 or later.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">Absolutely \u2014 let\u2019s go deeper and explore how <strong>file-scoped types<\/strong> in C# 12 interact with:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Source Generators<\/strong><\/li>\n\n\n\n<li><strong>Performance Profiling<\/strong><\/li>\n\n\n\n<li><strong>Advanced Compiler Diagnostics<\/strong><\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">We\u2019re going beyond the \u201cwhat\u201d and \u201cwhy\u201d here and into the \u201chow\u201d and \u201cunder the hood\u201d territory. So buckle up \u2014 this is where it gets interesting for folks who love tooling, introspection, and squeezing the most out of the language and runtime.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">File-Scoped Types + Source Generators<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Quick Primer: What Are Source Generators?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Source generators in C# (introduced in .NET 5 \/ C# 9) let you <strong>analyze code during compilation<\/strong> and <strong>generate additional C# source files<\/strong>. They\u2019re part of the Roslyn compiler and are used for things like:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Auto-generating boilerplate code<\/li>\n\n\n\n<li>Meta-programming<\/li>\n\n\n\n<li>Code weaving<\/li>\n\n\n\n<li>Strongly typed APIs from JSON, XML, etc.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">How Do File-Scoped Types Interact?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">File-scoped types present <strong>a visibility boundary<\/strong>. A source generator can still <strong>see<\/strong> and <strong>analyze<\/strong> them, <strong>but it cannot use them in generated code<\/strong> unless it generates code <strong>within the same file<\/strong> (which is generally not possible or advisable).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s break it down.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">You <em>Can See<\/em> File-Scoped Types in Generators<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">MyGenerator<\/span> : <span class=\"hljs-title\">ISourceGenerator<\/span>\n{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">Execute<\/span>(<span class=\"hljs-params\">GeneratorExecutionContext context<\/span>)<\/span>\n    {\n        <span class=\"hljs-keyword\">foreach<\/span> (<span class=\"hljs-keyword\">var<\/span> syntaxTree <span class=\"hljs-keyword\">in<\/span> context.Compilation.SyntaxTrees)\n        {\n            <span class=\"hljs-keyword\">var<\/span> semanticModel = context.Compilation.GetSemanticModel(syntaxTree);\n            <span class=\"hljs-keyword\">var<\/span> root = syntaxTree.GetRoot();\n\n            <span class=\"hljs-keyword\">var<\/span> fileScopedTypes = root.DescendantNodes()\n                .OfType&lt;ClassDeclarationSyntax&gt;()\n                .Where(cls =&gt;\n                    cls.Modifiers.Any(m =&gt; m.Text == <span class=\"hljs-string\">\"file\"<\/span>));\n\n            <span class=\"hljs-keyword\">foreach<\/span> (<span class=\"hljs-keyword\">var<\/span> type <span class=\"hljs-keyword\">in<\/span> fileScopedTypes)\n            {\n                <span class=\"hljs-comment\">\/\/ You can analyze it here<\/span>\n                <span class=\"hljs-keyword\">var<\/span> symbol = semanticModel.GetDeclaredSymbol(type);\n                context.ReportDiagnostic(Diagnostic.Create(\n                    <span class=\"hljs-keyword\">new<\/span> DiagnosticDescriptor(<span class=\"hljs-string\">\"FILE001\"<\/span>, <span class=\"hljs-string\">\"Found file-scoped type\"<\/span>, <span class=\"hljs-string\">\"Found {0}\"<\/span>, <span class=\"hljs-string\">\"Analyzer\"<\/span>, DiagnosticSeverity.Info, <span class=\"hljs-literal\">true<\/span>),\n                    type.GetLocation(),\n                    symbol?.Name\n                ));\n            }\n        }\n    }\n\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">Initialize<\/span>(<span class=\"hljs-params\">GeneratorInitializationContext context<\/span>)<\/span> { }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This works. You can <strong>inspect and report<\/strong> on file-scoped types.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">But You <em>Cannot Reference<\/em> Them in Generated Code<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s say you try to generate this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Wrapper<\/span>\n{\n    <span class=\"hljs-keyword\">private<\/span> fileScopedTypeInstance = <span class=\"hljs-keyword\">new<\/span> MyFileScopedHelper(); <span class=\"hljs-comment\">\/\/ \u274c This won\u2019t compile<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The compiler will throw an error:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">The type <span class=\"hljs-string\">'MyFileScopedHelper'<\/span> <span class=\"hljs-keyword\">is<\/span> not accessible <span class=\"hljs-keyword\">in<\/span> <span class=\"hljs-keyword\">this<\/span> context because it <span class=\"hljs-keyword\">is<\/span> file-scoped.<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Workaround or Best Practice?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of referencing file-scoped types directly, use them as <strong>internal implementation details<\/strong>. Structure your generated code to interact through <strong>public or internal interfaces<\/strong>, keeping the file-scoped types truly hidden.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Good Practice:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Let file-scoped types serve internal, per-file logic.<\/li>\n\n\n\n<li>Let source generators target broader-scope types or generate companions (e.g., partial classes or attributes).<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">File-Scoped Types + Performance Profiling<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">File-scoped types <strong>do not affect runtime performance directly<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But they can contribute to <strong>performance in the following indirect ways<\/strong>:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Cleaner IL and Smaller Assemblies<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Since file-scoped types aren\u2019t visible outside their file, the compiler can:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Emit them with non-public visibility<\/li>\n\n\n\n<li>Avoid placing them in metadata exposed to the rest of the assembly<\/li>\n\n\n\n<li>Potentially improve JIT compilation (due to reduced method lookup scope)<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s peek at the IL (Intermediate Language) difference.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Example<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-comment\">\/\/ FileScopedHelper.cs<\/span>\nfile <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">FileScopedHelper<\/span>\n{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">DoWork<\/span>(<span class=\"hljs-params\"><\/span>)<\/span> =&gt; Console.WriteLine(<span class=\"hljs-string\">\"Work!\"<\/span>);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Now, compile and inspect with <strong>ILSpy<\/strong> or <strong>dotPeek<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You\u2019ll see the type marked with:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">.<span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">private<\/span> <span class=\"hljs-title\">auto<\/span> <span class=\"hljs-title\">ansi<\/span> <span class=\"hljs-title\">beforefieldinit<\/span> <span class=\"hljs-title\">FileScopedHelper<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Contrast this with <code>internal<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">.<span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">assembly<\/span> <span class=\"hljs-title\">auto<\/span> <span class=\"hljs-title\">ansi<\/span> <span class=\"hljs-title\">beforefieldinit<\/span> <span class=\"hljs-title\">InternalHelper<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The <code>private<\/code> accessibility reduces the metadata footprint and can help <strong>minimize JIT time<\/strong>, especially in <strong>large assemblies with hundreds of internal helpers<\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Performance Profiling with dotTrace or PerfView<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">When you run performance profilers (like JetBrains dotTrace or Microsoft PerfView), file-scoped types appear <strong>only in the context of their containing method\/class<\/strong>. This can reduce noise in trace logs or call graphs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This becomes incredibly helpful when debugging performance in <strong>large enterprise codebases<\/strong>, where thousands of internal types can show up and obscure the real hot paths.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Advanced Compiler Diagnostics and File-Scoped Types<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Want to go deeper? Let\u2019s talk about how the compiler processes file-scoped types and how you can get more insight during build time.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Roslyn Diagnostic Analyzers<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">You can write your own <strong>custom Roslyn analyzer<\/strong> to:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Enforce usage of <code>file<\/code> modifier for certain internal classes<\/li>\n\n\n\n<li>Flag accidental overexposure of helper types<\/li>\n\n\n\n<li>Ensure tests don&#8217;t reference non-test file types<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Example: A diagnostic that warns if an <code>internal<\/code> class is only used in one file and should be <code>file<\/code>.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-comment\">\/\/ Pseudo-code<\/span>\n<span class=\"hljs-keyword\">if<\/span> (type <span class=\"hljs-keyword\">is<\/span> <span class=\"hljs-keyword\">internal<\/span> &amp;&amp; UsageCount(type) == <span class=\"hljs-number\">1<\/span>)\n{\n    ReportDiagnostic(\n        <span class=\"hljs-string\">\"Consider marking this type as `file` scoped to improve encapsulation\"<\/span>\n    );\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">These diagnostics can run as part of CI pipelines and help enforce architectural boundaries.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Compiler Switches and Logging<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">You can compile with detailed output using:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">dotnet build \/p:EmitCompilerGeneratedFiles=<span class=\"hljs-literal\">true<\/span> \/p:LangVersion=preview<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This will show generated files and make it easier to inspect compiler behavior around <code>file<\/code> scoped types.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">IDE, Analyzer, and Dev Workflow Considerations<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\u2714 Visual Studio \/ JetBrains Rider<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Syntax highlighting for <code>file<\/code> modifier<\/li>\n\n\n\n<li>Intellisense <strong>excludes file-scoped types from autocomplete outside the file<\/strong><\/li>\n\n\n\n<li>Go-to-definition (<code>F12<\/code>) will not resolve if you&#8217;re in another file<\/li>\n\n\n\n<li><code>CodeLens<\/code> will show <code>0 references<\/code> from other files<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">\u2714 Analyzers<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If you&#8217;re using Roslyn analyzers (e.g., Microsoft.CodeAnalysis.NetAnalyzers), expect future rules to recommend <code>file<\/code> in appropriate cases \u2014 especially as adoption increases.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Exercise 1: Roslyn Analyzer to Recommend <code>file<\/code> Modifier<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">We\u2019ll write a <strong>Roslyn Diagnostic Analyzer<\/strong> that scans your code for top-level <code>internal<\/code> types used only in their own file, and suggests converting them to <code>file<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This includes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Creating a custom diagnostic<\/li>\n\n\n\n<li>Checking references via <code>ISymbol<\/code><\/li>\n\n\n\n<li>Verifying usage count<\/li>\n\n\n\n<li>Reporting a diagnostic when appropriate<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Prerequisites<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">You\u2019ll need:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>.NET SDK 7.0 or later<\/li>\n\n\n\n<li>Visual Studio 2022 (with &#8220;Roslyn SDK&#8221; workload)<\/li>\n\n\n\n<li>Optional: <a href=\"https:\/\/github.com\/dotnet\/roslyn-sdk\" target=\"_blank\" rel=\"noreferrer noopener\">Roslyn SDK Templates<\/a><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Create your analyzer project:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">dotnet <span class=\"hljs-keyword\">new<\/span> analyzer -n FileScopedTypeAnalyzer\ncd FileScopedTypeAnalyzer<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Analyzer Code<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Edit <code>FileScopedTypeAnalyzer.cs<\/code> like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">using<\/span> System.Collections.Immutable;\n<span class=\"hljs-keyword\">using<\/span> Microsoft.CodeAnalysis;\n<span class=\"hljs-keyword\">using<\/span> Microsoft.CodeAnalysis.Diagnostics;\n<span class=\"hljs-keyword\">using<\/span> Microsoft.CodeAnalysis.CSharp;\n<span class=\"hljs-keyword\">using<\/span> Microsoft.CodeAnalysis.CSharp.Syntax;\n\n<span class=\"hljs-keyword\">namespace<\/span> <span class=\"hljs-title\">FileScopedTypeAnalyzer<\/span>\n{\n    &#91;<span class=\"hljs-meta\">DiagnosticAnalyzer(LanguageNames.CSharp)<\/span>]\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">FileScopedTypeAnalyzer<\/span> : <span class=\"hljs-title\">DiagnosticAnalyzer<\/span>\n    {\n        <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">const<\/span> <span class=\"hljs-keyword\">string<\/span> DiagnosticId = <span class=\"hljs-string\">\"FILE001\"<\/span>;\n\n        <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">readonly<\/span> DiagnosticDescriptor Rule = <span class=\"hljs-keyword\">new<\/span>(\n            DiagnosticId,\n            <span class=\"hljs-string\">\"Use 'file' modifier for single-file internal type\"<\/span>,\n            <span class=\"hljs-string\">\"Internal type '{0}' is only used in this file; consider using 'file' modifier\"<\/span>,\n            <span class=\"hljs-string\">\"Encapsulation\"<\/span>,\n            DiagnosticSeverity.Info,\n            isEnabledByDefault: <span class=\"hljs-literal\">true<\/span>);\n\n        <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">override<\/span> ImmutableArray&lt;DiagnosticDescriptor&gt; SupportedDiagnostics =&gt; ImmutableArray.Create(Rule);\n\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">override<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">Initialize<\/span>(<span class=\"hljs-params\">AnalysisContext context<\/span>)<\/span>\n        {\n            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);\n            context.EnableConcurrentExecution();\n\n            context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.NamedType);\n        }\n\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">AnalyzeSymbol<\/span>(<span class=\"hljs-params\">SymbolAnalysisContext context<\/span>)<\/span>\n        {\n            <span class=\"hljs-keyword\">var<\/span> namedType = (INamedTypeSymbol)context.Symbol;\n\n            <span class=\"hljs-comment\">\/\/ Only interested in internal top-level types<\/span>\n            <span class=\"hljs-keyword\">if<\/span> (namedType.DeclaredAccessibility != Accessibility.Internal ||\n                namedType.ContainingType != <span class=\"hljs-literal\">null<\/span> ||\n                namedType.Locations.Length == <span class=\"hljs-number\">0<\/span>)\n                <span class=\"hljs-keyword\">return<\/span>;\n\n            <span class=\"hljs-keyword\">var<\/span> location = namedType.Locations&#91;<span class=\"hljs-number\">0<\/span>];\n            <span class=\"hljs-keyword\">var<\/span> syntaxTree = location.SourceTree;\n            <span class=\"hljs-keyword\">if<\/span> (syntaxTree == <span class=\"hljs-literal\">null<\/span>) <span class=\"hljs-keyword\">return<\/span>;\n\n            <span class=\"hljs-keyword\">var<\/span> references = context.Compilation\n                .GetSemanticModel(syntaxTree)\n                .SyntaxTree\n                .GetRoot()\n                .DescendantNodes()\n                .OfType&lt;IdentifierNameSyntax&gt;()\n                .Where(id =&gt; id.Identifier.Text == namedType.Name)\n                .ToList();\n\n            <span class=\"hljs-comment\">\/\/ Used only once (declaration), not referenced elsewhere in project<\/span>\n            <span class=\"hljs-keyword\">if<\/span> (references.Count &lt;= <span class=\"hljs-number\">1<\/span>)\n            {\n                <span class=\"hljs-keyword\">var<\/span> diagnostic = Diagnostic.Create(Rule, namedType.Locations&#91;<span class=\"hljs-number\">0<\/span>], namedType.Name);\n                context.ReportDiagnostic(diagnostic);\n            }\n        }\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Test the Analyzer<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Build your solution and reference your analyzer from another test project. Add a type like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-comment\">\/\/ Helper.cs<\/span>\n<span class=\"hljs-keyword\">internal<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Helper<\/span> { }<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">You\u2019ll now get:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udca1 <em>\u201cInternal type &#8216;Helper&#8217; is only used in this file; consider using &#8216;file&#8217; modifier\u201d<\/em><\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\ude80 Exercise 2: Profiling JIT with File-Scoped Types<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">While file-scoped types <strong>don\u2019t directly speed up runtime<\/strong>, they can <strong>reduce metadata, improve code locality<\/strong>, and help the <strong>JIT compiler<\/strong> generate tighter call trees \u2014 especially in large projects.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We\u2019ll demonstrate this using a simplified example + PerfView.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">\ud83d\udd2c Setup: Simulating Internal Helper Overload<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Create a large number of internal classes in a namespace:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-comment\">\/\/ InternalHelpers.cs<\/span>\n<span class=\"hljs-keyword\">namespace<\/span> <span class=\"hljs-title\">InternalLib<\/span>\n{\n    <span class=\"hljs-keyword\">internal<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Helper1<\/span> { <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">int<\/span> <span class=\"hljs-title\">Foo<\/span>(<span class=\"hljs-params\"><\/span>)<\/span> =&gt; <span class=\"hljs-number\">1<\/span>; }\n    <span class=\"hljs-keyword\">internal<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Helper2<\/span> { <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">int<\/span> <span class=\"hljs-title\">Foo<\/span>(<span class=\"hljs-params\"><\/span>)<\/span> =&gt; <span class=\"hljs-number\">2<\/span>; }\n    ...\n    <span class=\"hljs-keyword\">internal<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Helper500<\/span> { <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">int<\/span> <span class=\"hljs-title\">Foo<\/span>(<span class=\"hljs-params\"><\/span>)<\/span> =&gt; <span class=\"hljs-number\">500<\/span>; }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Then benchmark a method calling one of them:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">Main<\/span>(<span class=\"hljs-params\"><\/span>)<\/span>\n{\n    <span class=\"hljs-keyword\">var<\/span> h = <span class=\"hljs-keyword\">new<\/span> Helper243();\n    Console.WriteLine(h.Foo());\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Now switch the type to:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-comment\">\/\/ Helper243.cs<\/span>\nfile <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Helper243<\/span> { <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">int<\/span> <span class=\"hljs-title\">Foo<\/span>(<span class=\"hljs-params\"><\/span>)<\/span> =&gt; <span class=\"hljs-number\">243<\/span>; }<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Profiling with PerfView or dotTrace<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Use these steps:<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">PerfView<\/h4>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Launch <code>PerfView.exe<\/code><\/li>\n\n\n\n<li>Run your app with <strong>JIT + CPU Sampling<\/strong> enabled<\/li>\n\n\n\n<li>Search for <code>Helper243.Foo<\/code> in the call tree<\/li>\n\n\n\n<li>Check:\n<ul class=\"wp-block-list\">\n<li>JIT time<\/li>\n\n\n\n<li>JIT-compiled method count<\/li>\n\n\n\n<li>Assembly load size<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">You\u2019ll typically notice:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u2705 Slightly <strong>smaller method metadata size<\/strong><br>\u2705 Reduced clutter in <strong>symbol table<\/strong><br>\u2705 Tighter JIT compilation trees<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In massive assemblies (1000s of internal helpers), this translates to <strong>measurable startup improvements<\/strong>, especially in ASP.NET Core apps with cold starts.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Final Thoughts<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">File-scoped types in C# 12 are a deceptively simple feature that can have a huge impact on code quality. They give you:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Better encapsulation<\/li>\n\n\n\n<li>Cleaner namespaces<\/li>\n\n\n\n<li>Tighter control over type visibility<\/li>\n\n\n\n<li>More maintainable, modular files<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">They\u2019re not flashy, but they\u2019re powerful. Like many great features in C#, they\u2019re about giving you more control and better defaults.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The beauty of this feature lies in its restraint\u2014it\u2019s not about doing more, but about doing less with more intention. Keeping things local. Scoped. Minimal. Clean.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So next time you write a helper type that no one else should care about, do yourself a favor:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-19\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">file <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">MyInternalThing<\/span> { ... }<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-19\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">And move on with a cleaner, safer, saner codebase.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>C# has evolved significantly over the years, and each version brings new features aimed at improving readability, maintainability, and developer productivity. With C# 12, one of the more subtle but powerful additions is File-Scoped Types. Now, if you&#8217;re just hearing about this for the first time, you might be wondering: \u201cFile-scoped what now? Aren\u2019t types [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_genesis_hide_title":false,"_genesis_hide_breadcrumbs":false,"_genesis_hide_singular_image":false,"_genesis_hide_footer_widgets":false,"_genesis_custom_body_class":"","_genesis_custom_post_class":"","_genesis_layout":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[8,4],"tags":[],"class_list":["post-2238","post","type-post","status-publish","format-standard","category-csharp","category-programming-languages","entry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.8 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>File-Scoped Types in C# 12: Cleaner Namespaces, Safer Encapsulation<\/title>\n<meta name=\"description\" content=\"In C# 12, file-scoped types refer to a new kind of type visibility\u2014types that are visible only within the file in which they are declared\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.w3computing.com\/articles\/file-scoped-types-csharp-12-cleaner-namespaces-safer-encapsulation\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"File-Scoped Types in C# 12: Cleaner Namespaces, Safer Encapsulation\" \/>\n<meta property=\"og:description\" content=\"In C# 12, file-scoped types refer to a new kind of type visibility\u2014types that are visible only within the file in which they are declared\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.w3computing.com\/articles\/file-scoped-types-csharp-12-cleaner-namespaces-safer-encapsulation\/\" \/>\n<meta property=\"article:published_time\" content=\"2025-04-21T17:44:53+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-04-21T17:44:59+00:00\" \/>\n<meta name=\"author\" content=\"w3compadmin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"w3compadmin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"TechArticle\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/file-scoped-types-csharp-12-cleaner-namespaces-safer-encapsulation\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/file-scoped-types-csharp-12-cleaner-namespaces-safer-encapsulation\\\/\"},\"author\":{\"name\":\"w3compadmin\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#\\\/schema\\\/person\\\/a550b3e20d78bb4f79b7c6b7b53f0561\"},\"headline\":\"File-Scoped Types in C# 12: Cleaner Namespaces, Safer Encapsulation\",\"datePublished\":\"2025-04-21T17:44:53+00:00\",\"dateModified\":\"2025-04-21T17:44:59+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/file-scoped-types-csharp-12-cleaner-namespaces-safer-encapsulation\\\/\"},\"wordCount\":2367,\"articleSection\":[\"C#\",\"Programming Languages\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/file-scoped-types-csharp-12-cleaner-namespaces-safer-encapsulation\\\/\",\"url\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/file-scoped-types-csharp-12-cleaner-namespaces-safer-encapsulation\\\/\",\"name\":\"File-Scoped Types in C# 12: Cleaner Namespaces, Safer Encapsulation\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#website\"},\"datePublished\":\"2025-04-21T17:44:53+00:00\",\"dateModified\":\"2025-04-21T17:44:59+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#\\\/schema\\\/person\\\/a550b3e20d78bb4f79b7c6b7b53f0561\"},\"description\":\"In C# 12, file-scoped types refer to a new kind of type visibility\u2014types that are visible only within the file in which they are declared\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/file-scoped-types-csharp-12-cleaner-namespaces-safer-encapsulation\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/file-scoped-types-csharp-12-cleaner-namespaces-safer-encapsulation\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/file-scoped-types-csharp-12-cleaner-namespaces-safer-encapsulation\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Articles Home\",\"item\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Programming Languages\",\"item\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/programming-languages\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"File-Scoped Types in C# 12: Cleaner Namespaces, Safer Encapsulation\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#website\",\"url\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/\",\"name\":\"Developer Articles Hub\",\"description\":\"\",\"alternateName\":\"Developer Articles\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#\\\/schema\\\/person\\\/a550b3e20d78bb4f79b7c6b7b53f0561\",\"name\":\"w3compadmin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/wp-content\\\/litespeed\\\/avatar\\\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1782562654\",\"url\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/wp-content\\\/litespeed\\\/avatar\\\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1782562654\",\"contentUrl\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/wp-content\\\/litespeed\\\/avatar\\\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1782562654\",\"caption\":\"w3compadmin\"},\"sameAs\":[\"http:\\\/\\\/w3computing.com\\\/articles\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"File-Scoped Types in C# 12: Cleaner Namespaces, Safer Encapsulation","description":"In C# 12, file-scoped types refer to a new kind of type visibility\u2014types that are visible only within the file in which they are declared","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.w3computing.com\/articles\/file-scoped-types-csharp-12-cleaner-namespaces-safer-encapsulation\/","og_locale":"en_US","og_type":"article","og_title":"File-Scoped Types in C# 12: Cleaner Namespaces, Safer Encapsulation","og_description":"In C# 12, file-scoped types refer to a new kind of type visibility\u2014types that are visible only within the file in which they are declared","og_url":"https:\/\/www.w3computing.com\/articles\/file-scoped-types-csharp-12-cleaner-namespaces-safer-encapsulation\/","article_published_time":"2025-04-21T17:44:53+00:00","article_modified_time":"2025-04-21T17:44:59+00:00","author":"w3compadmin","twitter_card":"summary_large_image","twitter_misc":{"Written by":"w3compadmin","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"TechArticle","@id":"https:\/\/www.w3computing.com\/articles\/file-scoped-types-csharp-12-cleaner-namespaces-safer-encapsulation\/#article","isPartOf":{"@id":"https:\/\/www.w3computing.com\/articles\/file-scoped-types-csharp-12-cleaner-namespaces-safer-encapsulation\/"},"author":{"name":"w3compadmin","@id":"https:\/\/www.w3computing.com\/articles\/#\/schema\/person\/a550b3e20d78bb4f79b7c6b7b53f0561"},"headline":"File-Scoped Types in C# 12: Cleaner Namespaces, Safer Encapsulation","datePublished":"2025-04-21T17:44:53+00:00","dateModified":"2025-04-21T17:44:59+00:00","mainEntityOfPage":{"@id":"https:\/\/www.w3computing.com\/articles\/file-scoped-types-csharp-12-cleaner-namespaces-safer-encapsulation\/"},"wordCount":2367,"articleSection":["C#","Programming Languages"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.w3computing.com\/articles\/file-scoped-types-csharp-12-cleaner-namespaces-safer-encapsulation\/","url":"https:\/\/www.w3computing.com\/articles\/file-scoped-types-csharp-12-cleaner-namespaces-safer-encapsulation\/","name":"File-Scoped Types in C# 12: Cleaner Namespaces, Safer Encapsulation","isPartOf":{"@id":"https:\/\/www.w3computing.com\/articles\/#website"},"datePublished":"2025-04-21T17:44:53+00:00","dateModified":"2025-04-21T17:44:59+00:00","author":{"@id":"https:\/\/www.w3computing.com\/articles\/#\/schema\/person\/a550b3e20d78bb4f79b7c6b7b53f0561"},"description":"In C# 12, file-scoped types refer to a new kind of type visibility\u2014types that are visible only within the file in which they are declared","breadcrumb":{"@id":"https:\/\/www.w3computing.com\/articles\/file-scoped-types-csharp-12-cleaner-namespaces-safer-encapsulation\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.w3computing.com\/articles\/file-scoped-types-csharp-12-cleaner-namespaces-safer-encapsulation\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.w3computing.com\/articles\/file-scoped-types-csharp-12-cleaner-namespaces-safer-encapsulation\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Articles Home","item":"https:\/\/www.w3computing.com\/articles\/"},{"@type":"ListItem","position":2,"name":"Programming Languages","item":"https:\/\/www.w3computing.com\/articles\/programming-languages\/"},{"@type":"ListItem","position":3,"name":"File-Scoped Types in C# 12: Cleaner Namespaces, Safer Encapsulation"}]},{"@type":"WebSite","@id":"https:\/\/www.w3computing.com\/articles\/#website","url":"https:\/\/www.w3computing.com\/articles\/","name":"Developer Articles Hub","description":"","alternateName":"Developer Articles","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.w3computing.com\/articles\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.w3computing.com\/articles\/#\/schema\/person\/a550b3e20d78bb4f79b7c6b7b53f0561","name":"w3compadmin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.w3computing.com\/articles\/wp-content\/litespeed\/avatar\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1782562654","url":"https:\/\/www.w3computing.com\/articles\/wp-content\/litespeed\/avatar\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1782562654","contentUrl":"https:\/\/www.w3computing.com\/articles\/wp-content\/litespeed\/avatar\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1782562654","caption":"w3compadmin"},"sameAs":["http:\/\/w3computing.com\/articles"]}]}},"featured_image_src":null,"featured_image_src_square":null,"author_info":{"display_name":"w3compadmin","author_link":"https:\/\/www.w3computing.com\/articles\/author\/w3compadmin\/"},"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/posts\/2238","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/comments?post=2238"}],"version-history":[{"count":3,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/posts\/2238\/revisions"}],"predecessor-version":[{"id":2241,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/posts\/2238\/revisions\/2241"}],"wp:attachment":[{"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/media?parent=2238"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/categories?post=2238"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/tags?post=2238"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}