1
1
// Licensed to the .NET Foundation under one or more agreements.
2
2
// The .NET Foundation licenses this file to you under the MIT license.
3
3
4
+ using System . Buffers . Binary ;
4
5
using System . Runtime . InteropServices ;
5
6
6
7
namespace Microsoft . EntityFrameworkCore . ValueGeneration ;
@@ -35,17 +36,29 @@ public class SequentialGuidValueGenerator : ValueGenerator<Guid>
35
36
/// <returns>The value to be assigned to a property.</returns>
36
37
public override Guid Next ( EntityEntry entry )
37
38
{
38
- Span < byte > guidBytes = stackalloc byte [ 16 ] ;
39
- var succeeded = Guid . NewGuid ( ) . TryWriteBytes ( guidBytes ) ;
40
- Check . DebugAssert ( succeeded , "Could not write Guid to Span" ) ;
41
- var incrementedCounter = Interlocked . Increment ( ref _counter ) ;
42
- Span < byte > counterBytes = stackalloc byte [ sizeof ( long ) ] ;
43
- MemoryMarshal . Write ( counterBytes , in incrementedCounter ) ;
39
+ var guid = Guid . NewGuid ( ) ;
44
40
45
- if ( ! BitConverter . IsLittleEndian )
46
- {
47
- counterBytes . Reverse ( ) ;
48
- }
41
+ var counter = BitConverter . IsLittleEndian
42
+ ? Interlocked . Increment ( ref _counter )
43
+ : BinaryPrimitives . ReverseEndianness ( Interlocked . Increment ( ref _counter ) ) ;
44
+
45
+ var counterBytes = MemoryMarshal . AsBytes (
46
+ new ReadOnlySpan < long > ( in counter ) ) ;
47
+
48
+ // Guid uses a sequential layout where the first 8 bytes (_a, _b, _c)
49
+ // are subject to byte-swapping on big-endian systems when reading from
50
+ // or writing to a byte array (e.g., via MemoryMarshal or Guid constructors).
51
+ // The remaining 8 bytes (_d through _k) are interpreted as-is,
52
+ // regardless of endianness.
53
+ //
54
+ // Since we only modify the last 8 bytes of the Guid (bytes 8–15),
55
+ // byte order does not affect the result.
56
+ //
57
+ // This allows us to safely use MemoryMarshal.AsBytes to directly access
58
+ // and modify the Guid's underlying bytes without any extra conversions,
59
+ // which also slightly improves performance on big-endian architectures.
60
+ var guidBytes = MemoryMarshal . AsBytes (
61
+ new Span < Guid > ( ref guid ) ) ;
49
62
50
63
guidBytes [ 08 ] = counterBytes [ 1 ] ;
51
64
guidBytes [ 09 ] = counterBytes [ 0 ] ;
@@ -56,7 +69,7 @@ public override Guid Next(EntityEntry entry)
56
69
guidBytes [ 14 ] = counterBytes [ 3 ] ;
57
70
guidBytes [ 15 ] = counterBytes [ 2 ] ;
58
71
59
- return new Guid ( guidBytes ) ;
72
+ return guid ;
60
73
}
61
74
62
75
/// <summary>
0 commit comments