Shared libraries should not use System.Console. Besides an assumption that they are running in a process with an attached console, which may not be correct, the library really has no idea what its hosting process is using its STDIO streams for. A console app may be using a TUI where blindly writing to the console could have nasty side effects on the user experience. Or maybe the process runs as an invisible child process and STDIO is being used for inter-process communication (IPC) with some well-defined protocol, in which case interfering with STDIO would corrupt the data stream.

Why would libraries want to use System.Console anyway? Well, sometimes they want to log text that wouldn’t fit well into an Exception.Message. There may be other reasons. But unless that’s a primary scenario for the library (e.g. the library delivers a TUI) and/or is very well documented as writing to the console, it shouldn’t be done.

What should libraries do instead? The simplest way is for your API to accept or offer a TraceSource and log to that. Let the application attach a TraceListener to that if they want to direct your log messages to their console, or a file, or their Debug output window, etc.

When you’re developing a library, especially if you’re doing so on a team, how do you help ensure no one slips in calls to System.Console? There’s an analyzer for that!

  <ItemGroup>
    <PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.4" PrivateAssets="all" />
  </ItemGroup>

  <ItemGroup>
    <AdditionalFiles Include="BannedSymbols.txt" />
  </ItemGroup>

Now we just need to create a BannedSymbols.txt file with the following content:

T:System.Console;Libraries should not use STDIO streams. Leave that to the application.

With that now in place, the C# compiler will now produce a compile error anytime code is introduced that uses the Console.

Learn more about the BannedApiAnalyzers.