Reputation: 109732
I'd like to be able to use the new C#11 required
modifier with .NET Framework 4.8 and .Net Standard 2.0.
I'm using Visual Studio 2022 version 17.4. Is this possible?
Upvotes: 21
Views: 6800
Reputation: 109732
This is possible, but you will have to provide some types that the compiler needs in order to support it. You will also need to compile using Visual Studio 2022 version 17.4 or later, along with C# 11.
The necessary types are defined in .NET 7.0, but they don't all exist in earlier versions. These types are as follows:
static class IsExternalInit
- Introduced with C# 9 and .NET 5.class RequiredMemberAttribute
- Introduced with C# 11 and .NET 7.class CompilerFeatureRequiredAttribute
- Introduced with C# 11 and
.NET 7.These types must all be defined within the System.Runtime.CompilerServices
namespace. They should also be declared as internal
- if they are public
and defined within a class library that is referenced by a .NET 7 project, you'll get multiply-defined errors.
You can declare them as follows - this must be included in every .NET 4.8 or .NET Standard 2.0 assembly that uses the required
modifier:
using System.ComponentModel;
namespace System.Runtime.CompilerServices
{
#if !NET5_0_OR_GREATER
[EditorBrowsable(EditorBrowsableState.Never)]
internal static class IsExternalInit {}
#endif // !NET5_0_OR_GREATER
#if !NET7_0_OR_GREATER
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
internal sealed class RequiredMemberAttribute : Attribute {}
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)]
internal sealed class CompilerFeatureRequiredAttribute : Attribute
{
public CompilerFeatureRequiredAttribute(string featureName)
{
FeatureName = featureName;
}
public string FeatureName { get; }
public bool IsOptional { get; init; }
public const string RefStructs = nameof(RefStructs);
public const string RequiredMembers = nameof(RequiredMembers);
}
#endif // !NET7_0_OR_GREATER
}
namespace System.Diagnostics.CodeAnalysis
{
#if !NET7_0_OR_GREATER
[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)]
internal sealed class SetsRequiredMembersAttribute : Attribute {}
#endif
}
Note the use of the #if
directives to support different targets.
(Incidentally, the declaration of internal static class IsExternalInit {}
also enables the use of the record
type and the init only
property setter feature that was introduced in C# 9.)
Once you've added the definitions above to a .NET Framework 4.8 or .NET Standard 2.0 assembly, you can use the required
modifier in that assembly even if the assembly is referenced by a different .NET Framework 4.8 or .NET Standard 2.0 assembly that doesn't provide those definitions (although you'd still need to provide the definitions in that other assembly if you want to use the required
modifier for classes defined within that assembly).
Caveats:
required
modifier must be compiled with Visual Studio 2022 version 17.4 or later.11
or latest
using <LangVersion>11</LangVersion>
or <LangVersion>latest</LangVersion>
.required
modifier via a NuGet package.References:
Required
modifer reference - The Microsoft documentation for required
.Upvotes: 44