Dealing with error CS0518: 'IsExternalInit not defined or imported'
A quick explanation of how to deal with error CS0518, which may occur when trying to use init setters on frameworks earlier than .NET 5.0

If you're trying to use the new C# 9 init setters on a framework earlier than .NET 5.0, you may have encountered the following error:

Error CS0518: Predefined type 'System.Runtime.CompilerServices.IsExternalInit' is not defined or imported

The reason you're seeing this error is because init setters are a C# 9 feature that are only officially supported when targeting .NET 5.0 (or higher). The compiler requires that the IsExternalInit type is defined in order for the feature to work. IsExternalInit is defined in .NET 5.0, so everything works out of the box there. IsExternalInit is not defined in any of the earlier frameworks, so init setters can't be used without a workaround. Luckily, the workaround is very easy.

To "fix" this error, all you have to do is define IsExternalInit in your code. It's a simple marker class, so something like this will suffice:

using System.ComponentModel;

namespace System.Runtime.CompilerServices
{
    [EditorBrowsable(EditorBrowsableState.Never)]
    internal static class IsExternalInit { }
}

However, if you're multi-targeting .NET 5.0 in your project, your .NET 5.0 build will end up with an unnecessary duplicate of the IsExternalInit class.

There are a couple of options to work around that. You can remove this file from your compile target when targeting .NET 5.0, as per Daniel Cazzulino's suggestion:

<ItemGroup>
  <Compile Remove="IsExternalInit.cs" Condition="'$(TargetFramework)' == 'net5.0'" />
</ItemGroup>

Or, you can use preprocessor directives to ensure that your custom IsExternalInit definition is only included when necessary, as per Brant Burnett's suggestion:

#if NETSTANDARD2_0 || NETSTANDARD2_1 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NETCOREAPP3_0 || NETCOREAPP3_1 || NET45 || NET451 || NET452 || NET6 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48

using System.ComponentModel;

namespace System.Runtime.CompilerServices
{
    [EditorBrowsable(EditorBrowsableState.Never)]
    internal static class IsExternalInit { }
}

#endif

Either of these approaches are fine. It's up to personal taste.

There's a very enlightening discussion on GitHub that covers this situation in more detail, but the approaches above should be sufficient to help you resolve this issue.

I hope you found this blog post helpful.


Posted by Matthew King on 11 December 2020
Permission is granted to use all code snippets under CC BY-SA 3.0 (just like StackOverflow), or the MIT license - your choice!
If you enjoyed this post, and you want to show your appreciation, you can buy me a beverage on Ko-fi or Stripe