-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Prefer static ReadOnlySpan<byte> properties over static readonly byte[] fields #33780
Prefer static ReadOnlySpan<byte> properties over static readonly byte[] fields #33780
Comments
Estimates:
|
Should this only trigger for byte or for other primitives as well? |
byte, sbyte, and bool |
The analyzer makes sense, but the fixer is potentially problematic. Take a look at the referenced PR from above, where after converting the byte array to a ROS, the places where it was used had to be heavily adjusted. Applying a fixer would cause build failures if methods that are exclusive for that data type were being called ( Question:
Cases that the analyzer would handle: // Yes
private static readonly byte[] s_byte = new byte[] { ... };
internal static readonly byte[] s_byte = new byte[] { ... };
// No
public static readonly byte[] s_byte = new byte[] { ... }; // public
protected static readonly byte[] s_byte = new byte[] { ... }; // protected
private readonly byte[] s_byte = new byte[] { ... }; // no static
private static byte[] s_byte = new byte[] { ... }; // no readonly |
Until #24961 is implemented and Roslyn optimizes with it, Roslyn only applies the relevant optimization to single-byte primitive types, i.e. byte, sbyte, and bool. |
This issue has been automatically marked |
Removing the label so it doesn't get autoclosed by the bot. This could be ready to mark as ready for review, keeping in mind that the analyzer would be limited to @buyaa-n @stephentoub any additional thoughts you'd like to share before I apply the label? |
@stephentoub Is there an option to get static read-only ros backing memory region by reflection? Can we actually consider adding const modifier to such ros? Like with { 1, 2, 3, 4, 5 } value |
This is a question for C#. I suggest opening an issue/proposal in the csharplang repo, if there isn't one already. |
We do :-) |
I would prefer this for other things like But that could be for really much any |
Interesting I tried applying it to the parts of my classes where I would really like that relaxed since that could result in improvements to static class members in terms of eliminating an Edit: The compiler seems to not like this: internal static class Tree
{
internal static ReadOnlySpan<byte> BlOrder { get; } = CreateBlOrder();
// other static properties.
// other things.
private static ReadOnlySpan<byte> CreateBlOrder()
=> new byte[]
{
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15,
};
} And when I try to wrap that property in a dummy |
You can't store a span in a field, which this does: internal static ReadOnlySpan<byte> BlOrder { get; } = CreateBlOrder(); This would need to be: internal static ReadOnlySpan<byte> BlOrder => CreateBlOrder(); |
Category: Performance
|
I would like to be assigned to this, please. |
@terrajobst Should be Edit: Actually this might be intentional per #33780 (comment). I'm not sure. |
@jaredpar It seems like internal class C
{
private unsafe static ReadOnlySpan<byte> Data
{
get
{
return new ReadOnlySpan<byte>(System.Runtime.CompilerServices.Unsafe.AsPointer(ref <PrivateImplementationDetails>.A498EFA8D0759E7B704095853DB9BC1EF8CF65AF37BED9D006C4B2917E695061), 5);
}
}
}
[CompilerGenerated]
internal sealed class <PrivateImplementationDetails>
{
[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 5)]
private struct __StaticArrayInitTypeSize=5
{
}
internal static readonly __StaticArrayInitTypeSize=5 A498EFA8D0759E7B704095853DB9BC1EF8CF65AF37BED9D006C4B2917E695061/* Not supported: data(00 00 01 02 03) */;
} |
That's correct. I frequently forget that this pattern is optimized to be non-allocating. |
That is until you turn the span into a list or array, then it allocates a copy. However what if I did not want to allocate an array but instead operate on the data in the span, (and modify it) I am assuming then it would modify it for then whenever the application ever uses that property again to get a span, it would get not the original one, but the modified one which would be an regression on my end that I would have to be careful with while at the same time I want to reduce allocations to as little to nothing if possible. |
It's a ReadOnlySpan (or sbyte, bool), so any modification should be prohibited in safe code. |
It seems that this change can also help to avoid some potential bug: byte[] arr = new DataWrapper().GetArray();
arr[0] = 2;
Console.WriteLine(new DataWrapper().GetArray()[0]);
class DataWrapper
{
private static readonly byte[] array = new byte[] { 1 };
public byte[] GetArray() => array;
} |
With a pattern like
private static readonly byte[] s_array = new byte[] { ... }
where thestatic readonly byte[]
isinternal
/private
, all consumers ofs_array
could instead operate on a span, and the field is initialized to a newbyte[]
of constant values, it can be changed instead tostatic ReadOnlySpan<byte> Data => new byte[] { ... }
, and the C# compiler will optimize the implementation.Category: Performance
The text was updated successfully, but these errors were encountered: