Skip to content

Increase priority of MemoryMarshal.AsRef<T>(Span<T>) with [OverloadResolutionPriority] #122217

@kindermannhubert

Description

@kindermannhubert

Description

There is:

ref T AsRef<T>(Span<byte> span)
ref readonly T AsRef<T>(ReadOnlySpan<byte> span)

in System.Runtime.InteropServices.MemoryMarshal and I propose adding [OverloadResolutionPriority(1)] attribute to the AsRef<T>(Span<byte>) overload as follows:

[OverloadResolutionPriority(1)]
ref T AsRef<T>(Span<byte> span)

ref readonly T AsRef<T>(ReadOnlySpan<byte> span)

That would solve the issue described below.

Unfortunately, the usage of the first overload is impaired by changes from C# 14. I've described the issue here: dotnet/roslyn#81528 (comment) and have been told the change is intended.

Assuming we have:

public struct MyStruct
{
    public static implicit operator Span<byte>(in MyStruct value) => default;
}

Then, with C# 13 the following worked:

void M()
{
    // Overload AsRef<byte>(Span<byte>) is selected.
    ref var r = ref MemoryMarshal.AsRef<byte>(x);
}

but with C# 14 following happens:

void M()
{
    // Does not compile. Overload AsRef<byte>(ReadOnlySpan<byte>) is selected, so `ref var` cannot be used.
    ref var r = ref MemoryMarshal.AsRef<byte>(x);

    // Compiles, but that's not what I want (I want 'ref var' and not 'ref readonly var').
    ref readonly var r2 = ref MemoryMarshal.AsRef<byte>(x);
}

The workaround is to use the explicit cast:

void M()
{
    // Compiles, but an explicit cast is needed to select the correct overload.
    ref var r = ref MemoryMarshal.AsRef<byte>((Span<byte>)x);
}

Reproduction Steps

public struct MyStruct
{
    public static implicit operator Span<byte>(in MyStruct value) => default;
}

void M()
{
    ref var r = ref MemoryMarshal.AsRef<byte>(x);
}

Expected behavior

The following should compile with C# 14 (as it compiled with C# 13).

public struct MyStruct
{
    public static implicit operator Span<byte>(in MyStruct value) => default;
}

void M()
{
    ref var r = ref MemoryMarshal.AsRef<byte>(x);
}

Actual behavior

The following does not compile with C# 14.

public struct MyStruct
{
    public static implicit operator Span<byte>(in MyStruct value) => default;
}

void M()
{
    ref var r = ref MemoryMarshal.AsRef<byte>(x);
}

Regression?

It worked with C# 13.

Known Workarounds

Use explicit cast (instead of implicit) to Span<byte>.

Configuration

No response

Other information

No response

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions