9

C# 11 File Scoped Types

 2 years ago
source link: https://blog.ndepend.com/c-11-file-scoped-types/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

C# 11 File Scoped Types

C# 11 File Scoped Type Title

C#11 added the file scoped types feature: a new file modifier that can be applied to any type definition to restrict its usage to the current file. This way we can have several classes with the same name (namespace.name) in a single project. This is shown through the project below that contains two classes named ConsoleApp1.Answer :

C# 11 File Scope Type

Here are a few remarks:

  • The types with the file modifier can be indirectly accessed outside of their source file. In the program above we rely on the internal classes InternalClassFromFile1 and InternalClassFromFile2 to run both Answer classes from Program.
  • Such file class can also be indirectly used outside its source file through an interface this way:
namespace ConsoleApp1 {
   file class Answer : IAnswer {
      public string GetFileScopeSecret() => "Answer from File1.cs";
   internal interface IAnswer {
      string GetFileScopeSecret();
   static class InternalClassFromFile1 {
      internal static IAnswer GetAnswer() => new Answer();
  • Any kind of type can be marked with the file modifier: class, interface, record, structenumdelegate.
  • file cannot be used with another modifier like internal or public.
  • file partial can be used as long as all the type definitions belong to the same file:
namespace ConsoleApp1 {
   file static partial class Answer {
      internal static string GetFileScopeSecret()
         => "Answer from File1.cs";
   file static partial class Answer {
      internal static string AnotherGetFileScopeSecret()
         => "Another Answer from File1.cs";
  • The file modifier doesn’t apply to types nested in a parent type. Also it doesn’t apply to methods properties, events and fields but the language design note explains: “Leaves the design space open for non-type file-scoped members to come along later.”
  • As the screenshot below shows, it is possible to have in a project, a single internal or public class with full name ConsoleApp1.Answer, and one or several file ConsoleApp1.Answer. The only drawback is that the public class cannot be used within source files containing a file scoped class.

C# 11 File Scope Type No Collision With Another Type

Why this feature?

Let’s underline that namespace remains the preferred way to avoid type name collision. However we can imagine several use cases for this feature:

  • Generated code: Typically generated templates often use the same class name again and again, like ItemInfo or DataSet. To prevent collision we had to either nest an Item class in a parent class or maintain an index in name for each generated version, like Item1, Item2 … Thus the keyword file can significantly ease code generation.
  • Extension method: Extension method is nowadays a popular language construct for C# developers. However there can be extension method naming collision. With this file visibility restriction it is now easy to have extension methods restricted to a single file. Another common issue with extension method -solved by this file visibility restriction- is that they pollute intellisense dropdowns.
  • Nested class: To solve the naming collision within a project, a common solution mentioned above is that we used to declare private nested classes. However this is not clean code because an extra indentation level is added, and too much indentation clutters code. Thus the file keyword will help with this concern.
  • Module and Encapsulation: Typically what you consider as a module or a component is not a single class but a few highly cohesive types. For encapsulation purposes a pattern was to nest private implementation details within private nested classes and types. This file scope makes such encapsulation pattern cleaner.
  • Test: Often tests structure is standardized and each test class has its own DataSet class for example. Here also instead of declaring classes nested in test classes, the file restriction will help.

However keep in mind that a file restricted class won’t be visible from tests. Those must be considered as private implementation (black box) and must be tested through internal or public classes that access them.

Quick tip: You can test your internal implementations by tagging your projects with the System.Runtime.CompilerServices.InternalsVisibleToAttribute. This way you don’t have to declare these classes as public just for testing purposes.

[assembly: InternalsVisibleTo("NDepend.Test.Unit, PublicKey=002400000480...")]

What the compiler generates?

The C# compiler renames types with the file restriction this way: <SourceFileNameWithoutExtension>F$index$_TypeName. The index is incremented to avoid collision when a project has several source files with the same name containing file scoped types.

Thanks to the <> characters there is no risk for such class to be consumed from elsewhere than its file. This common compiler renaming pattern is called special naming and is used in a number of scenario including async/await , lambda, anonymous method, anonymous type.

Interestingly enough, when analyzing a bunch of projects within a solution, NDepend doesn’t try to change special names. Thus the NDepend dependency graph of the small program shown in the first screenshot above looks like this:

C# 11 File Scope Type Decompiled

Again another great C# featurette that will help us write even cleaner code :))

My dad being an early programmer in the 70's, I have been fortunate to switch from playing with Lego, to program my own micro-games, when I was still a kid. Since then I never stop programming.

I graduated in Mathematics and Software engineering. After a decade of C++ programming and consultancy, I got interested in the brand new .NET platform in 2002. I had the chance to write the best-seller book (in French) on .NET and C#, published by O'Reilly and also did manage some academic and professional courses on the platform and C#.

Over my consulting years I built an expertise about the architecture, the evolution and the maintenance challenges of large & complex real-world applications. It seemed like the spaghetti & entangled monolithic legacy concerned every sufficiently large team. As a consequence, I got interested in static code analysis and started the project NDepend in 2004.

Nowadays NDepend is a full-fledged Independent Software Vendor (ISV). With more than 12.000 client companies, including many of the Fortune 500 ones, NDepend offers deeper insight and full control on their application to a wide range of professional users around the world.

I live with my wife and our twin kids Léna and Paul in the beautiful island of Mauritius in the Indian Ocean.


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK