Here's a summary of what's new in the .NET Runtime in this preview release:
Runtime updates in .NET 9 Preview 4:
- What's new in the .NET Runtime in .NET 9 documentation
.NET 9 Preview 4:
The UnsafeAccessorAttribute
feature allows unsafe access to type members that are unaccessible to the caller. This feature was designed in .NET 8 but implemented without support for generic parameters. In .NET 9, based on community feedback, we prioritized adding this support and it is now available for CoreCLR and native AOT scenarios. Remaining work, including support in mono, can be found here.
Usage example:
public class Class<T>
{
private T _field;
private void M<U>(T t, U u) { }
}
class Accessors<V>
{
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_field")]
public extern static ref V GetSetPrivateField(Class<V> c);
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "M")]
public extern static void CallM<W>(Class<V> c, V v, W w);
}
public void AccessGenericType(Class<int> c)
{
ref int f = ref Accessors<int>.GetSetPrivateField(c);
Accessors<int>.CallM<string>(c, 1, string.Empty);
}
Two new attributes make it possible to define feature switches that can be used to toggle areas of functionality in .NET libraries, with support for removing unused features when trimming or native AOT compiling. For example, these attributes are used in the definitions of RuntimeFeature.IsDynamicCodeSupported
and RuntimeFeature.IsDynamicCodeCompiled
FeatureSwitchDefinitionAttribute
can be used to treat a feature switch property as a constant when trimming:
public class Feature
{
[FeatureSwitchDefinition("Feature.IsSupported")]
internal static bool IsSupported => AppContext.TryGetSwitch("Feature.IsSupported", out bool isEnabled) ? isEnabled : true;
internal static Implementation() => ...;
}
This allows dead code guarded by the switch to be removed. For example:
if (Feature.IsSupported)
Feature.Implementation();
When the app is trimmed with the following feature settings, Feature.IsSupported
is treated as false
, and Feature.Implementation
is removed.
<ItemGroup>
<RuntimeHostConfigurationOption Include="Feature.IsSupported" Value="false" Trim="true" />
</ItemGroup>
FeatureGuardAttribute
can be used to treat a feature switch property as a guard for code annotated with RequiresUnreferencedCodeAttribute
, RequiresAssemblyFilesAttribute
, or RequiresDynamicCodeAttribute
:
public class Feature
{
[FeatureGuard(typeof(RequiresDynamicCodeAttribute))]
internal static bool IsSupported => RuntimeFeature.IsDynamicCodeSupported;
[RequiresDynamicCode("Feature requires dynamic code support.")]
internal static Implementation() => ...; // Uses dynamic code
}
Because the IsSupported
property returns false whenever dynamic code is not supported, Feature.IsSupported
can be used as a guard for methods that requires dynamic code at runtime. The FeatureGuardAttribute
makes this known to the trim analyzer and the trimming tools. For example:
if (Feature.IsSupported)
Feature.Implementation();
When built with <PublishAot>true</PublishAot>
, the call to Feature.Implementation()
will not produce analyzer warning IL3050, and Feature.Implementation
will be removed when publishing.