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

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions