-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
What's new in .NET 7 Preview 5 [WIP] #7441
Comments
dotnet/runtime#67917 by @steveharter Update: see #7441 (comment) below |
ObservabilityExpose performant ActivityEvent and ActivityLink tags enumerator methods dotnet/runtime#68056The exposed methods can be used in the perf critical scenarios to enumerate the Tags objects without any extra allocations and with fast items access. namespace System.Diagnostics
{
public partial struct ActivityLink
{
public Activity.Enumerator<KeyValuePair<string, object?>> EnumerateTagObjects();
}
public partial struct ActivityEvent
{
public Activity.Enumerator<KeyValuePair<string, object?>> EnumerateTagObjects();
}
} Sample Code var tags = new List<KeyValuePair<string, object?>>()
{
new KeyValuePair<string, object?>("tag1", "value1"),
new KeyValuePair<string, object?>("tag2", "value2"),
};
ActivityLink link = new ActivityLink(default, new ActivityTagsCollection(tags));
foreach (ref readonly KeyValuePair<string, object?> tag in link.EnumerateTagObjects())
{
// Consume the link tags without any extra allocations or value copying.
}
ActivityEvent e = new ActivityEvent("SomeEvent", tags: new ActivityTagsCollection(tags));
foreach (ref readonly KeyValuePair<string, object?> tag in e.EnumerateTagObjects())
{
// Consume the event's tags without any extra allocations or value copying.
} |
System.Text.JsonPolymorphism dotnet/runtime#63747System.Text.Json now supports serializing and deserializing polymorphic type hierarchies using attribute annotations: [JsonDerivedType(typeof(Derived))]
public class Base
{
public int X { get; set; }
}
public class Derived : Base
{
public int Y { get; set; }
} This configuration enables polymorphic serialization for Base value = new Derived();
JsonSerializer.Serialize<Base>(value); // { "X" : 0, "Y" : 0 } Note that this does not enable polymorphic deserialization since the payload would be roundtripped as Base value = JsonSerializer.Deserialize<Base>(@"{ ""X"" : 0, ""Y"" : 0 }");
value is Derived; // false Using Type DiscriminatorsTo enable polymorphic deserialization, users need to specify a type discriminator for the derived class: [JsonDerivedType(typeof(Base), typeDiscriminator: "base")]
[JsonDerivedType(typeof(Derived), typeDiscriminator: "derived")]
public class Base
{
public int X { get; set; }
}
public class Derived : Base
{
public int Y { get; set; }
} Which will now emit JSON along with type discriminator metadata: Base value = new Derived();
JsonSerializer.Serialize<Base>(value); // { "$type" : "derived", "X" : 0, "Y" : 0 } which can be used to deserialize the value polymorphically: Base value = JsonSerializer.Deserialize<Base>(@"{ ""$type"" : ""derived"", ""X"" : 0, ""Y"" : 0 }");
value is Derived; // true Type discriminator identifiers can also be integers, so the following form is valid: [JsonDerivedType(typeof(Derived1), 0)]
[JsonDerivedType(typeof(Derived2), 1)]
[JsonDerivedType(typeof(Derived3), 2)]
public class Base { }
JsonSerializer.Serialize<Base>(new Derived2()); // { "$type" : 1, ... } Utf8JsonReader.CopyString dotnet/runtime#54410Until today, int valueLength = reader.HasReadOnlySequence ? checked((int)ValueSequence.Length) : ValueSpan.Length;
char[] buffer = ArrayPool<char>.Shared.Rent(valueLength);
int charsRead = reader.CopyString(buffer);
ReadOnlySpan<char> source = buffer.Slice(0, charsRead);
ParseUnescapedString(source); // handle the unescaped JSON string
ArrayPool<char>.Shared.Return(buffer); Or if handling UTF-8 is preferable: ReadOnlySpan<byte> source = stackalloc byte[0];
if (!reader.HasReadOnlySequence && !reader.ValueIsEscaped)
{
source = reader.ValueSpan; // No need to copy to an intermediate buffer if value is span without escape sequences
}
else
{
int valueLength = reader.HasReadOnlySequence ? checked((int)ValueSequence.Length) : ValueSpan.Length;
Span<byte> buffer = valueLength <= 256 ? stackalloc byte[256] : new byte[valueLength];
int bytesRead = reader.CopyString(buffer);
source = buffer.Slice(0, bytesRead);
}
ParseUnescapedBytes(source); Source Generation improvementsAdded source generation support for |
System.IO.StreamAdd Stream ReadExactly and ReadAtLeast dotnet/runtime#16598One of the most common mistakes when using To help this situation, we have added new methods to the base namespace System.IO;
public partial class Stream
{
public void ReadExactly(Span<byte> buffer);
public void ReadExactly(byte[] buffer, int offset, int count);
public ValueTask ReadExactlyAsync(Memory<byte> buffer, CancellationToken cancellationToken = default);
public ValueTask ReadExactlyAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken = default);
public int ReadAtLeast(Span<byte> buffer, int minimumBytes, bool throwOnEndOfStream = true);
public ValueTask<int> ReadAtLeastAsync(Memory<byte> buffer, int minimumBytes, bool throwOnEndOfStream = true, CancellationToken cancellationToken = default);
} The new Exampleusing FileStream f = File.Open("readme.md");
byte[] buffer = new byte[100];
f.ReadExactly(buffer); // guaranteed to read 100 bytes from the file The new Exampleusing FileStream f = File.Open("readme.md");
byte[] buffer = new byte[100];
int bytesRead = f.ReadAtLeast(buffer, 10);
// 10 <= bytesRead <= 100 |
New Roslyn analyzer and fixer for Regex source generatorIn his blog post about Regular Expression performance, @stephentoub described the new source generator that will be shipping in .NET 7 to allow you to to statically generate regular expression logic at compile time. In order to take advantage of the source generator, you have to find places in your code where it could be used and make the necessary modification to the code in those places. This sounds like the perfect job for a Roslyn analyzer and fixer, and we've added this in Preview 5. AnalyzerThe new analyzer is inbox in .NET 7, and will search for uses of
Here is an example of how the diagnostic is displayed in Visual StudioCode FixerThe code fixer is also shipping inbox in .NET 7, and will work for all diagnostics emitted by the analyzer. By clicking on "Show potential fixes" on the diagnostic logged by the analyzer, you will see an option called "Convert to 'RegexGenerator'". This is the code fixer and when you apply the changes, it will let you override the name to use for the generated method. It would also replace the invocation code that was causing the diagnostic with an invocation to the new source generated method. Here is an example of how the code fixer gets applied in Visual StudioWe are hoping that this analyzer and fixer will help with the visibility of the source generator and will also make onboarding to it easier. Please try it out and let us know if you have any feedback. |
Generic MathIn .NET 6 we previewed a feature known as "generic math": https://devblogs.microsoft.com/dotnet/preview-features-in-net-6-generic-math/. Since then, we have made continuous improvements to the implementation and responded to various feedback from the community in order to ensure that relevant scenarios are possible and the necessary APIs are available. For more information on the changes and available APIs see https://devblogs.microsoft.com/dotnet/dotnet-7-generic-math/. |
CodeGenCommunity PRs@SingleAccretion made 23 PR contributions during Preview 5 with some highlighted items below:
@sandreenko completed allowing StoreLclVar src to be IND/FLD PR#59315. See contributions from @anthonycanino, @aromaa and @ta264 in the below sections. Arm64
Loop Optimization
x86/x64 OptimizationsThere were a number of optimizations targetted for x86/x64 platforms:
Modernize JITAs more and more community contributors participate in the JIT code base, it is increasingly getting important to restructure our code and modernize it in order to allow our contributors to easily ramp up and rapidly develop code. The above allowed us to remove an old limitation in the JIT’s inliner when inlining functions with parameters of byte/sbyte/short/ushort type, resulting in better code quality:
As .NET has become a more and more popular platform for writing high-performance code the coding style has changed. One area where the JIT was lacking was in its understanding of unsafe code involving reads and writes of structs and struct fields. @SingleAccretion contributed great changes in this area by switching the JIT’s internal model to a more general “physical” model. This paves the way for the JIT to better reason about unsafe code using features like struct reinterpretation. Other minor cleanups were also made to simplify the JIT IR:
General OptimizationsA few general JIT optimizations were done in below PRs: |
I think we may also want to mention that crossgen2 now has been published with NativeAOT? /cc: @agocke |
An interesting question -- it does demonstrate that we're shipping programs using NativeAOT, but crossgen is also effectively private surface area, so I'm not sure if it would be helpful to most blog readers |
System.Reflection performance improvements when invoking membersThe overhead of using reflection to invoke a member (whether a method, constructor or a property getter\setter) has been substantially reduced when the invoke is done several times on the same member. Typical gains are 3-4x faster. See dotnet/runtime#67917 for more information. Using the using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System.Reflection;
namespace ReflectionBenchmarks
{
internal class Program
{
static void Main(string[] args)
{
BenchmarkRunner.Run<InvokeTest>();
}
}
public class InvokeTest
{
private MethodInfo? _method;
private object[] _args = new object[1] { 42 };
[GlobalSetup]
public void Setup()
{
_method = typeof(InvokeTest).GetMethod(nameof(InvokeMe), BindingFlags.Public | BindingFlags.Static)!;
}
[Benchmark]
// This went from ~116ns to ~39ns or 3x (66%) faster.
public void InvokeSimpleMethod() => _method!.Invoke(obj: null, new object[] { 42 });
[Benchmark]
// This went from ~106ns to ~26ns or 4x (75%) faster.
public void InvokeSimpleMethodWithCachedArgs() => _method!.Invoke(obj: null, _args);
public static int InvokeMe(int i) => i;
}
} |
@tarekgh Can you please provide some sample code for the above? |
@AngelosP I have updated my comment #7441 (comment) to include the code sample. Please let me know if you need anything else. |
All submission and changes are in the latest draft, thank you all! <3 |
@AngelosP one minor erratum concerning the IAsyncEnumerable example: // It now works and no longer throws NotSupportedException
JsonSerializer.Serialize(new MyPoco { Data = ... }, MyContext.MyPoco); The above is not support and will always throw, since IAsyncEnumerable requires one of the async serialization methods. For the sake of correctness it should probably read: // It now works and no longer throws NotSupportedException
await JsonSerializer.SerializeAsync(new MyPoco { Data = ... }, MyContext.MyPoco); |
.NET 7 GA is available. Closing these pre-release issues. |
What's new in .NET 7 Preview 5
This issue is for teams to highlight work for the community that will release .NET 7 Preview 5
To add content, use a new conversation entry. The entry should include the team name and feature title as the first line as shown in the template below.
Preview 1: #7106
Preview 2: #7107
Preview 3: #7108
Preview 4: #7378
Preview 5: #7441
Preview 6: #7454
Preview 7: #7455
The text was updated successfully, but these errors were encountered: